Note, I\'ve read about the new routing features as part of WebApi 2.2 to allow for inheritance of routes. This does not seem to solve my particular issue, however. It seems
As @HazardouS identifies, @Grbinho's answer is hard-coded. Borrowing from this answer to inheritance of direct routing and from @HazardouS, I wrote this object
public class InheritableDirectRouteProvider : DefaultDirectRouteProvider {}
Then overrode the following methods, hoping RoutePrefixAttribute would get inherited:
protected override IReadOnlyList GetControllerRouteFactories(HttpControllerDescriptor controllerDescriptor)
{
// Inherit route attributes decorated on base class controller
// GOTCHA: RoutePrefixAttribute doesn't show up here, even though we were expecting it to.
// Am keeping this here anyways, but am implementing an ugly fix by overriding GetRoutePrefix
return controllerDescriptor.GetCustomAttributes(true);
}
protected override IReadOnlyList GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
// Inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes(true);
}
Sadly, per the gotcha comment, RoutePrefixAttribute doesn't show up in the factory list. I didn't dig into why, in case anyone wants to research a little deeper into this. So I kept those methods for future compatibility, and overrode the GetRoutePrefix method as follows:
protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor)
{
// Get the calling controller's route prefix
var routePrefix = base.GetRoutePrefix(controllerDescriptor);
// Iterate through each of the calling controller's base classes that inherit from HttpController
var baseControllerType = controllerDescriptor.ControllerType.BaseType;
while(typeof(IHttpController).IsAssignableFrom(baseControllerType))
{
// Get the base controller's route prefix, if it exists
// GOTCHA: There are two RoutePrefixAttributes... System.Web.Http.RoutePrefixAttribute and System.Web.Mvc.RoutePrefixAttribute!
// Depending on your controller implementation, either one or the other might be used... checking against typeof(RoutePrefixAttribute)
// without identifying which one will sometimes succeed, sometimes fail.
// Since this implementation is generic, I'm handling both cases. Preference would be to extend System.Web.Mvc and System.Web.Http
var baseRoutePrefix = Attribute.GetCustomAttribute(baseControllerType, typeof(System.Web.Http.RoutePrefixAttribute))
?? Attribute.GetCustomAttribute(baseControllerType, typeof(System.Web.Mvc.RoutePrefixAttribute));
if (baseRoutePrefix != null)
{
// A trailing slash is added by the system. Only add it if we're prefixing an existing string
var trailingSlash = string.IsNullOrEmpty(routePrefix) ? "" : "/";
// Prepend the base controller's prefix
routePrefix = ((RoutePrefixAttribute)baseRoutePrefix).Prefix + trailingSlash + routePrefix;
}
// Traverse up the base hierarchy to check for all inherited prefixes
baseControllerType = baseControllerType.BaseType;
}
return routePrefix;
}
Notes: