Overload web api action method based on parameter type

This kind of scenario is not well supported by the standard routing methods.

You may want to use attribute based routing instead as this gives you a lot more flexibility.

Specifically look at the route constraints where you can route by the type:

// Type constraints
[GET("Int/{x:int}")]
[GET("Guid/{x:guid}")]

Anything else will turn into a bit of a hack… e.g.

If you did attempt it using standard routing you would probably need to route to the correct action via it’s name, then use reg ex’s constraints (e.g. guid) to route to the required default action.

Controllers:

public class MyController : ApiController
{
   [ActionName("GetById")]
   public Foo Get(int id) { //whatever }

   [ActionName("GetByString")]
   public Foo Get(string id) { //whatever }

   [ActionName("GetByGUID")]
   public Foo Get(Guid id)  { //whatever }
}

Routes:

        //Should match /api/My/1
        config.Routes.MapHttpRoute(
            name: "DefaultDigitApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { action = "GetById" },
            constraints: new { id = @"^\d+$" } // id must be digits
        );

        //Should match /api/My/3ead6bea-4a0a-42ae-a009-853e2243cfa3
        config.Routes.MapHttpRoute(
            name: "DefaultGuidApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { action = "GetByGUID" },
            constraints: new { id = @"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$" } // id must be guid
        );

        //Should match /api/My/everything else
        config.Routes.MapHttpRoute(
            name: "DefaultStringApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { action = "GetByString" }
        );

Updated

I would normally use a POST if doing a FromBody (perhaps use the FromUri with the model instead) but your requirements could be met by adding the following.

For the controller

    [ActionName("GetAll")]
    public string Get([FromBody]MyFooSearch model)
    {
         if (model != null)
        {
            //search criteria at api/my
        }
        //default for api/my
    }

    //should match /api/my
    config.Routes.MapHttpRoute(
                name: "DefaultCollection",
                routeTemplate: "api/{controller}",
                defaults: new { action = "GetAll" }
            );

Leave a Comment