Basic Routing for WebAPI is trivial. It's the same as for MVC, except for
MapHttpRoute, instead of MapRouteWhat's rather more difficult is thinking of dealing with Versioning….
Basic routing assumes your webAPI Controllers will be in the route of the app.
WebAPI Template, orGet, Put, etc. MapHttpRoute (not MapRoute which is MVC concept):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 ApplicationStart method, but instead uses a AppStart\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}
);
}
}
It would be poor planning to release an APIs to external clients that is not versioned.
Code wise, versioning implies you will have:
Url resourse wise, there are two schools of thought:
After studying the issue (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.
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:
With the above solution, one can:
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:
area default.IHttpControllerSelector.