ASP.NET MVC3 and 404’s for Area Controllers

So I’m a big fan of ASP.NET MVC, and the general idea of convention over configuration, but I spent a few hours late last night fighting with something, and the Google was no help, so hopefully this helps someone else…

The situation:

I have ASP.NET MVC3 project, and I created an Area for my json API.  In my area I create a simple controller called CategoriesController, and I registered some routes in my AreaRegistration…

//handles get for a list of all categories
context.MapRoute(
    "ListCategories",
    "API/Categories",
    new { controller = "Categories", action = "List" }
);

I used the very awesome MvcRouteUnitTester (on Nuget) to write unit tests to make sure this route was working. All systems go!

Before I started writing tests against the actual controller, I used a browser to hit http://localhost/myapp/API/Categories – which should match this route, and spit back some “hello world” json. I get a 404.

Even with the unit tests, I decided to pull in the RouteDebugger NuGet package, just to make sure that the routes were working, and that showed that all was good

routes

So, I’m stumped. No Exceptions, everything seems to line up, but still a 404.

After about 15 minutes of useless Googling, I remember that I’ve got logging setup in this project, and that’s in my Global.asax.cs and tied into Application_Error…

protected void Application_Error()
{
    Exception lastException = Server.GetLastError();
    var logger = DependencyResolver.Current.GetService<ILogger>();
    logger.Fatal(lastException);
}

SO I look in the log… and find this error

The controller for path ‘/statsme/API/Categories/List’ was not found or does not implement IController.

(full trace because this will help Google index this when others go lookin)…

Message :The controller for path '/statsme/API/Categories/List' was not found or does not implement IController.
Source :System.Web.Mvc
Stack Trace :   at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
   at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<BeginProcessRequest>b__2()
   at System.Web.Mvc.SecurityUtil.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a()
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust[TResult](Func`1 func)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
TargetSite :System.Web.Mvc.IController GetControllerInstance(System.Web.Routing.RequestContext, System.Type)

Ok, WTF? CategoriesController inherits from a BaseController which inherits from Controller, so we’re clear on the IController bit. I know the class is there… what is going on?

Google… Google… more Google. Random hacking… cursing… Ah HA!

The issue was the namespace on my controller. Turns out that MVC has a convention that the area name is expected to be in the namespace of the controller.

So – I had StatsMe.API.CategoriesController, but MVC was looking for StatsMe.Areas.API.CategoriesController.

What finally tipped me off was some stuff in the RouteDebugger output…

namespaces

Annoying because the error message really could have helped out by saying “Hey – I’m looking for StatsMe.Areas.API.CategoriesController and I can’t find it”, rather than the very generic message it spit out.

Configuration Overriding Convention

As we all know, in MVC where there is a convention, there is a way to override this, and that’s in the route definition… like so…

context.MapRoute(
    "ListCategories",
    "API/Categories",
    new { controller = "Categories", action = "List" },
    new[] { "StatsMe.API.Controllers" }
);

Viola! Hope this helps someone else avoid a few hours of frustration.

Advertisement
This entry was posted in asp.net mvc. Bookmark the permalink.

7 Responses to ASP.NET MVC3 and 404’s for Area Controllers

  1. plioi says:

    Ah, the double-edge sword of convention-based APIs. It’s all good as long as the conventions are followed to the *letter*, and gets tricky when we stray from the convention. Things get extra frustrating when that *letter* wasn’t actually *written* anywhere! We should all take this experience to heart, and ensure that when we create conventions of our own (say for coworkers to follow on a project) we ensure that they’re both a) succinctly documented somewhere other than the original developer’s memory and b) verbose in their error messages when we inevitably miss a detail.

  2. Think we had something like that as well when first setting up areas in our MVC app.

    So, I wonder how many ASP.NET MVC based spatial web apps there are out there? Add this one that I worked on to the list: http://sarig.pir.sa.gov.au. Let me know your thoughts!

  3. Actually, it is clearly stated in every good book on ASP.NET MVC I’ve read. Sorry, but I find it hard to imagine to work with a framework without learning the basics first.

    • Dave Bouwman says:

      Thanks for that insight, and my apologies for wasting your time with this post. However, since not everyone has your diligent attention to detail, or the time to memorize all the minute details of every framework they work with, my intent was to help others who may run into this same issue.

      As for “not learning the basics” – having worked with MVC since preview 1, and having delivered >30 substantial web apps to clients ranging from small non-profits to multi-billion dollar global companies, I’m pretty sure that we have the basics down – thanks for your concern though.

      Cheers,

      Dave

  4. Craig says:

    Thanks for posting this. I went through a similar headache searching Google for and answer. Your post helped me to identify that the namespaces created by visual studio were the culprit… a very frustrating issue to identify from a ’404′ error. As for Dave’s comment, our team of developers glean from each others diverse experiences from front end development to integration development. It would be nice to have the time to read through books before jumping into something new but not a luxury many developers have.

    Cheers and Thanks for considering your piers.

  5. Michael Rut says:

    recommendation:
    Write a post about creating a super simple mapping application using a javascript api within the ASP.NET MVC3 architecture. Include basic functionality such as navigation, search, and selecting features.
    Love your blog… very helpful!

    • Dave Bouwman says:

      Michael,

      I like that but here’s the thing – the “basic” jsapi app can be done without a server side framework (it’s all JS talking to ArcGIS Server). The value in adding it into ASP.NET MVC is to utilize some server side goodies – security, custom data indexing/searching (i.e. with Lucene), real-time services or what have you, and typically that takes things past “super simple” and into the realm of data specific.

      We’ve got some DevSummit talks that will make their way into blog posts – 2 “real-time” demo apps implemented on node.js and asp.net mvc, as well as another on using BackboneJs in a map app. Since those are not at all related to client work, we can easily put them up on github, and the write posts dissecting them. All great things, but time is the limiting issue ;-)

      Cheers
      Dave

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s