Ramsey Ramsey - 13 days ago 7
ASP.NET (C#) Question

How to restrict Asp.net Web API / Owin discovery of controllers by namespace?

In the same project, I have two similar startup classes like this :

namespace X.A
{
public class AStartup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();

config.MapHttpAttributeRoutes();
config.EnsureInitialized();

appBuilder.UseWebApi(config);
}
}
}


and

namespace X.B
{
public class BStartup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();

config.MapHttpAttributeRoutes();
config.EnsureInitialized();

appBuilder.UseWebApi(config);
}
}
}


I also have several controllers, some are in namespace X.A... :

namespace X.A.SomePlace
{
[RoutePrefix("A/SomeRouting")]
public class Controller1 : ApiController
{
[Route("SomeMethod")]
[HttpPost]
[ResponseType(typeof(SomeMethodResponse))]
public IHttpActionResult GetParameters([FromBody] SomeMethodRequest request)
{
// Some code
}
}
}


... and others are in namespace X.B...:

namespace X.B.SomeOtherPlace
{
[RoutePrefix("B/AnotherRouting")]
public class Controller2 : ApiController
{
[Route("AnotherMethod")]
[HttpPost]
[ResponseType(typeof(AnotherMethodResponse))]
public IHttpActionResult AnotherMethod([FromBody] AnotherMethodRequest request)
{
// Another code
}
}
}


...and all controllers are in the same Asssembly.

Currently, all controllers get automagically registered to both API.
I would like to restrict the controller discovery by namespace (i.e. AStartup registers all controllers from X.A.... and BStartup registers all controllers from X.B...)

Is there a way to do this with MapHttpAttributeRoutes?

I would be also happy with another method that does not use attribute routes (i.e. if you have a method where I have to explicitely registers each controller programatically, that would work fine for me).

Answer

Following on peco answer, I've found the whole list of WEB API Services here: http://www.asp.net/web-api/overview/advanced/configuring-aspnet-web-api

The answer was to implement a custom IHttpControllerTypeResolver which is succinctly described at http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection.

I also found a lot of inspiration at http://www.strathweb.com/2013/08/customizing-controller-discovery-in-asp-net-web-api/

In case this is useful for someone else, here is the IHttpControllerTypeResolver I used:

namespace X.A
{
    public class AControllerTypeResolver : DefaultHttpControllerTypeResolver
    {
        public AControllerTypeResolver() : base(IsHttpEndpoint)
        {
        }

        private static bool IsHttpEndpoint(Type t)
        {    
            if (t == null) throw new ArgumentNullException("t");

            return t.IsClass &&
                t.IsVisible &&
                !t.IsAbstract &&
                typeof(ABaseController).IsAssignableFrom(t);
        }
    }
}

And I did the same for BControllerTypeResolver.

I did Replace the default service in AStartup like this:

config.Services.Replace(typeof(IHttpControllerTypeResolver), new AControllerTypeResolver());

I also had to make sure all my controllers are deriving from ABaseController (respectively BBaseController).