Search code examples
c#asp.netasp.net-web-apiasp.net-web-api2asp.net-web-api-routing

asp.net webapi2 catch all route


I'd like to have a catch all route that matches a general route prefix ("api/myaccount/1") execute if there are no more specific routes defined on other controllers (i.e "api/myaccount/1/feature") however I get the following exception when I do this:

Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.

As mentioned here: Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL it seems this may not be possible.

Wanting a default route to execute when no better one is found sounds pretty common so what am I missing? Do I need to hook lower in the pipeline or something...


FYI: I have the catch all working fine ("api/myaccount/1/{*uri}") it's just the being able to override it that's the problem.


Solution

  • Turns out this is pretty easy, I just needed to create a custom Controller Selector and override the GetControllerName function. That particular override is required because the method you would expect to override:

    HttpControllerDescriptor SelectController(HttpRequestMessage request) 
    

    does not just return the descriptor (or null if It can't find a match) as you may expect. The method actually handles the request for you and returns a 404 :/ However once you're aware of that it is trivial to work around and I was able to get the behavior I wanted using the code below:

    using System.Web.Http;
    using System.Web.Http.Dispatcher;
    
    public class CustomControllerSelector : DefaultHttpControllerSelector
    {
        public override string GetControllerName(HttpRequestMessage request)
        {
            var name =  base.GetControllerName(request);
            if(string.IsNullOrEmpty(name))
            {
                return "MyFeature"; //important not to include "Controller" suffix
            }
            return name;
        }
    }
    

    And add it to your configuration:

     public static class WebApiConfig
     {
         public static void Register(HttpConfiguration config)
         {
              ...
    
              config.Services.Replace(typeof(IHttpControllerSelector),
                  new CustomControllerSelector(config));
              ...
         }
     }