How to make more MapHttpRoutes for MVC 4 Api - asp.net-mvc

I have 2 API routes for my API atm, but I want to add more, and the way I am doing it it seems to overwrite each other, so in the code I pasted, only the CreateUser route works.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "CreateUser",
routeTemplate: "api/{controller}/{cUser}",
defaults: new
{
controller = "User",
action = "CreateUser",
cUser = RouteParameter.Optional
});
routes.MapHttpRoute(
name: "AllGames",
routeTemplate: "api/{controller}/{playerId}",
defaults: new
{
controller = "Game",
action = "GetAllGames",
playerId = RouteParameter.Optional
});
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}

I believe the pattern api/{controller}/{cUser} in "CreateUser" route is matching with rest of the controller actions because of its more generic pattern. Use specific controller name in the routes as "User" (api/User/{cUser}) and "Game" (api/Game/{playerId}). The more specific routes should be at the top and more generic at the bottom.
routes.MapHttpRoute(
name: "CreateUser",
routeTemplate: "api/User/{cUser}",
defaults: new
{
controller = "User",
action = "CreateUser",
cUser = RouteParameter.Optional
}
);
routes.MapHttpRoute(
name: "AllGames",
routeTemplate: "api/Game/{playerId}",
defaults: new
{
controller = "Game",
action = "GetAllGames",
playerId = RouteParameter.Optional
}
);

Related

API Controller in /Controllers instead of /api

I have various projects in a solution (ASP.Net MVC, domain, database, entities and Telerik Report Server WebApi).
The ASP.Net MVC is hosted at hostname/ and the Report Server at hostname/ReportServer/
All works fine except the Report Server.
It places the ReportsController API at
/ReportServer/Controllers/ReportsController
instead of
/ReportServer/api/ReportsController
I have created a simple test Solution with just a ASP.Net MVC and ReportServer, in theory with the same settings. This works, but I can't see what is causing this. All the routings, base class etc are the same.
Any ideas?
Instead of calling the default Telerik Reporting Route Registration function (ReportsControllerConfiguration.RegisterRoutes), you can write your own route registration procedure and call it from WebApiConfig.Register (before the DefaultApi route). For example:
private static void RegisterReportingRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(name: "Clients",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}",
defaults: new { controller = "MyCustomReports", action = "Clients", clientID = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "Instances",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/instances/{instanceID}",
defaults: new { controller = "MyCustomReports", action = "Instances", instanceID = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DocumentResources",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/resources/{resourceID}",
defaults: new { controller = "MyCustomReports", action = "DocumentResources" });
config.Routes.MapHttpRoute(
name: "DocumentActions",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/actions/{actionID}",
defaults: new { controller = "MyCustomReports", action = "DocumentActions" });
config.Routes.MapHttpRoute(
name: "DocumentPages",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/pages/{pageNumber}",
defaults: new { controller = "MyCustomReports", action = "DocumentPages" });
config.Routes.MapHttpRoute(
name: "DocumentInfo",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/info",
defaults: new { controller = "MyCustomReports", action = "DocumentInfo" });
config.Routes.MapHttpRoute(
name: "Documents",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}",
defaults: new { controller = "MyCustomReports", action = "Documents", documentID = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "Parameters",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/parameters",
defaults: new { controller = "MyCustomReports", action = "Parameters" });
config.Routes.MapHttpRoute(
name: "Formats",
routeTemplate: "ReportServer/Controllers/{controller}/clients/{clientID}/formats",
defaults: new { controller = "MyCustomReports", action = "Formats" });
config.Routes.MapHttpRoute( name: "EditingAndLayout", routeTemplate: "ReportServer/Controllers/{controller}/formats", defaults: new { controller = "MyCustomReports", action = "Formats" });
}
If the /ReportServer path is its own web application, instead of a route under the "/" application, then you can omit the "ReportServer/" part of the registration function above
The folder structure/name has no significance in case of ASP.Net Web API routing.
You don't need to put it in 'controller' folder or 'API' folder. If you noticed the routing configuration in WebAPI.config file, the default route template will be like 'api/{controller}/{id}' and this make your api routes working.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}", // <--
defaults: new { id = RouteParameter.Optional }
);

How can I integrate regex into my MapHttpRoute for WebApi

I currently have:
config.Routes.MapHttpRoute(
name: "AccountApiCtrl",
routeTemplate: "/api" + "/account/{action}/{id}",
defaults: new { controller = "accountapi", id = RouteParameter.Optional }
);
Which sends /api/account/myaction requests to accountapi controller. (it works great :-))
However, I'd rather not do this for each controller I have, is there a way I can use regex here so that I only have on declaration?
I.E so:
/api/account/action goes to controller: AccountApi
and
/api/user/action goes to controller: UserApi
i.e something along the lines of:
config.Routes.MapHttpRoute(
name: "ControllerApiMap",
routeTemplate: "/api" + "/{controller}/{action}/{id}",
defaults: new { controller = "{controller}+api", id = RouteParameter.Optional }
);
Following is one way of achieving this:
config.Services.Replace(typeof(IHttpControllerSelector), new CustomHttpControllerSelector(config));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
public class CustomHttpControllerSelector : DefaultHttpControllerSelector
{
public CustomHttpControllerSelector(HttpConfiguration config)
: base(config)
{
}
public override string GetControllerName(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
if (routeData.Values.ContainsKey("controller"))
{
return routeData.Values["controller"] + "api";
}
return base.GetControllerName(request);
}
}
Please, change as per below where you will be change regex:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // Route Pattern
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Default values for parameters
new { controller = "^H.*", action = "^Index$|^Contact$" } //Restriction for controller and action
);
Here, controller name start with H like Home and action start with Index or Contact, other's are ristricted.

ASP.NET MVC simplify routing

How can I simplify these routes?
config.Routes.MapHttpRoute(
name: "GetUsersRoute",
routeTemplate: "api/User",
defaults: new { controller = "User", action = "GetUsers" }
);
config.Routes.MapHttpRoute(
name: "GetUserRoute",
routeTemplate: "api/User/{id}",
defaults: new { controller = "User", action = "GetUser", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "GetEmailAddressRoute",
routeTemplate: "api/User/GetEmailAddress/{id}",
defaults: new { controller = "User", action="GetEmailAddress", id = RouteParameter.Optional }
);
/*** Default ***/
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I needed to add the GetEmailAddressRoute because the controller didn't know which action to take for a path like api/User/5. However, since then former routes like api/User don't lead to the correct action.
Some action signatures from the controller:
public Object GetUsers() { };
public Object GetUser(int id) { };
public HttpResponseMessage GetEmailAddress (int id) { };
But now I'd need to add another route for the Post actions. Is there a simpler way?
Update: What helped me for posting new users was to remove the action from the first route. Now it is
config.Routes.MapHttpRoute(
name: "GetUsersRoute",
routeTemplate: "api/User",
defaults: new { controller = "User" }
);
You can take advantage of the new routing attribute feature coming with web api 2 :
[Route("api/User")]
public Object GetUsers() { };
[Route("api/User/{id}")]
public Object GetUser(int id) { };
[Route("api/User/GetEmailAddress/{id}")]
public HttpResponseMessage GetEmailAddress (int id) { };

Can I set up a route that MVC will go to if no other routes match?

Here's a portion of my route config:
routes.MapHttpRoute(
name: ApiControllerActionAndId,
routeTemplate: "api/{controller}/{action}/{id}",
defaults: null, //defaults: new { id = RouteParameter.Optional } //,
constraints: new { id = #"^\d+$" }
);
routes.MapRoute(
"Account",
url: "Account/{action}/{id}",
defaults: new { controller = "Account", id = UrlParameter.Optional }
);
routes.MapRoute(
"spa",
"{section}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { section = #"home|questions|admin" });
The "spa" route is the very last route in the list.
Is there a way that I can change the last route called spa such that everything that does not match the routes before this goes to the controller Home and the action Index ?
routes.MapRoute(
"spa",
"{*path}",
new { controller = "Home", action = "Index"});

MVC route mapping: 1 URL pattern works only for exactly 1 controller

routes.MapRoute(
name: "GetAdressen",
url: "{controller}",
defaults: new { controller = "AdressenController", action = "GetAdressen"}
);
routes.MapRoute(
name: "GetEinsaetze",
url: "{controller}",
defaults: new { controller = "EinsaetzeController", action = "GetEinsaetze"}
);
In this case only /Adressen will work, and not also /Einsaetze
routes.MapRoute(
name: "GetEinsaetze",
url: "{controller}",
defaults: new { controller = "EinsaetzeController", action = "GetEinsaetze"}
);
routes.MapRoute(
name: "GetAdressen",
url: "{controller}",
defaults: new { controller = "AdressenController", action = "GetAdressen"}
);
In this case only /Einsaetze will work, and not also /Adressen
Why?
Use Like This
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "projectName.Controllers" });

Resources