# 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`.