Routing

Be careful with attribute routes in projects with both MVC and WebApi

Posted on Updated on

This is a pretty easy trap to fall into! I have been tearing my hair out recently trying to figure out why, in my pet project website, one of the controllers was not having any routes generated. I was able to inspect the generated routes during debugging by setting a breakpoint after the line

routes.MapMvcAttributeRoutes();

and inspecting the routes object. Sure enough routes for the HomeController and ChatController were there, but nothing for the BlogController. What could it be? Everything appeared to be set up correctly:

[<RoutePrefix "blog">]
type BlogController
    (
    _filterBlogPostsQuery: FilterBlogPostsQuery,
    _getBlogPostQuery: GetBlogPostQuery,
    _getAllBlogPostsQuery: GetAllBlogPostsQuery) =
 
    inherit MySiteController()
        
    [<Route "">]
    member this.Index() =
        task {
            let! posts = _getAllBlogPostsQuery()
 
            return this.View posts
        }

Eventually I figured it out after stumbling across this StackOverflow post: https://stackoverflow.com/questions/25727305/asp-mvc-5-attribute-routing-not-registering-routes/. It turns out that, when you have a project with both WebApi and MVC installed, you have two RoutePrefixAttribute classes and two RouteAttribute classes available; one in System.Web.Http and one in System.Web.Mvc. Make sure you’re referencing the right one!

This was also, perhaps, a consequence of using F#, and the fact that the Visual Studio tooling is not as feature-complete as the other languages; I didn’t get a warning from the compiler that there was a naming clash between these two Attributes, despite the fact that I had both the System.Web.Http and System.Web.Mvc namespaces opened at the top of the file. In the end, removing the System.Web.Http namespace was all that was needed to fix the problem.

Lesson learned. Still, it highlights a fragmentation issue between the Mvc and WebApi teams; one which I hope will be fixed in ASP.NET vNext (I assume this will be the case because MVC and WebApi will now share the same base controller).