# IT:AD:ASP.NET:WebAPI:HowTo:Configure WebAPI Routing # * [[../|(UP)]] {{indexmenu>.#2|nsort tsort}} ## Process ## Basic Routing for WebAPI is trivial. It's the same as for MVC, except for * Use `MapHttpRoute`, instead of `MapRoute` * Routes don't define default *Operaitions* (ie, you don't need to add Action=Index), as they rely on Verbs. * Reminder: Requests are mapped acording to Http Verb to methods that start with 'Get', 'Put', 'Delete', 'Post'. * There is no overload for defining the namespace if there are Controller name collisions, but it can be worked around: * [[IT/AD/ASP.NET/WebAPI/HowTo/Configure/WebAPI/Routing/defining/Namespaces]] * WebAPI does not support Areas out of the box. What's rather more difficult is thinking of dealing with Versioning.... ### Basics ### Basic routing assumes your webAPI Controllers will be in the route of the app. * Start a new MVC4 Applicaition. * Add a new WebAPI Controller * Can use a `WebAPI Template`, or * Methods will be called `Get`, `Put`, etc. * Register Route to WebAPI controller using `MapHttpRoute` (not `MapRoute` which is MVC concept): * If you use Areas (see below), you'll have to remember to add Area defaults. Example: //You can force the Controller if you want routes.MapHttpRoute( name: "ClientApi", routeTemplate: "client/detail/{param1}", defaults: new { controller = "ClientDetail" } ); //or use defaults: routes.MapHttpRoute( name:"DefaultApi" routeTemplate: "api/{controller}/{id}", defaults: new {id = RouteParameter.Optional} ); * The default route will prepend WebAPI controller paths with `api`, but you can change to anything. * In MVC4, one no longer uses the global.asax Application_Start method, but instead uses a App_Start\WebApiConfig class that is put there when you create your first WebAPI controller. Example: public class MvcApplication : System.Web.HttpApplication { ... WebApiConfig.Register(GlobalConfiguration.Configuration); } public static class WebApiConfig { public static void Register(HttpConfiguration config) { //or use defaults: routes.MapHttpRoute( name:"DefaultApi" routeTemplate: "api/{controller}/{id}", defaults: new {id = RouteParameter.Optional} ); } } ### Versioning ### It would be poor planning to release an APIs to external clients that is not versioned. Code wise, versioning implies you will have: * Controllers with the same name, * in different namespaces Url resourse wise, there are two schools of thought: * Version should be in the Url * Version should *not* be in the url, but instead be in the Accepts header. After studying the issue ([[IT/AD/ASP.NET/WebAPI/HowTo/Concepts/Versioning]]), I am concluding that the Accepts based solution would be purer, but the gain from the clarity of the url + the fact that the Accepts solution only works for some verbs, that versions should be in the url. #### Areas #### You can't have multiple Controllers with the same name in the root, so you have to use Areas. But Areas are not supported out of the box for WebAPI: * [[IT/AD/ASP.NET/WebAPI/HowTo/Configure/WebAPI/Routing/and/MVC/Areas]] With the above solution, one can: * define two or more Areas: "API.V1" and "API.V2" * Each area gets it's Name property set to "API.V1" and "API.V2" (with a dot, not a slash) * Each area defines its own routes, with the latest version's area getting default routes defined as well: Example: public class APIAreaRegistration : AreaRegistration { public override string AreaName { get { return "api.v1"; } } public override void RegisterArea(AreaRegistrationContext context) { var r = context.Routes.MapHttpRoute( "Admin_Api", "api/v1/{controller}/{id}", new {area = AreaName, id = RouteParameter.Optional}, null ); if (r.DataTokens == null) { r.DataTokens = new RouteValueDictionary(); } r.DataTokens["Namespaces"] = new string[] {"XAct.Spikes.WebAPI.I03.Areas.API.V1.Controllers"}; } } and public class API_V2AreaRegistration : AreaRegistration { public override string AreaName { get { return "API.V2"; } } public override void RegisterArea(AreaRegistrationContext context) { Route r; r = context.Routes.MapHttpRoute( "API.V2_default", "api/v2/{controller}/{id}", new {area = AreaName, id = RouteParameter.Optional }, null ); if (r.DataTokens == null) { r.DataTokens = new RouteValueDictionary(); } r.DataTokens["Namespaces"] = new string[] { "XAct.Spikes.WebAPI.I03.Areas.API.V2.Controllers" }; //In the latest api area, do the same, but for a route that has no Version defined. r = context.Routes.MapHttpRoute( "API.V2_defaultXXX", "api/{controller}/{id}", new {area = AreaName, id = RouteParameter.Optional }, null ); if (r.DataTokens == null) { r.DataTokens = new RouteValueDictionary(); } r.DataTokens["Namespaces"] = new string[] { "XAct.Spikes.WebAPI.I03.Areas.API.V2.Controllers" }; } } Notice: * We added the `area` default. * The Area name ('API.v2') must match a part of the namespace of the Controller it is trying to find: (eg: 'XAct.Spikes.WebAPI.I03.Areas.API.V2.Controllers') * Before it can work, you have to follow these instructions ([[IT/AD/ASP.NET/WebAPI/HowTo/Configure/WebAPI/Routing/and/MVC/Areas]]) to register a custom `IHttpControllerSelector`.