it:ad:asp.net:webapi:howto:configure_webapi_routing:home

IT:AD:ASP.NET:WebAPI:HowTo:Configure WebAPI Routing

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:
  • WebAPI does not support Areas out of the box.

What's rather more difficult is thinking of dealing with Versioning….

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 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:

  • 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 (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:

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 (Areas) to register a custom IHttpControllerSelector.
  • /home/skysigal/public_html/data/pages/it/ad/asp.net/webapi/howto/configure_webapi_routing/home.txt
  • Last modified: 2023/11/04 02:43
  • by 127.0.0.1