How to register an area using app_start or webactivator?

1.7k views Asked by At

I would like avoid having to call

AreaRegistration.RegisterAllAreas()

in my global.asax, because I'm trying to move all startup logic into individual classes inside of the App_Start folder. However, I've been unsuccessful in getting this to work. The first option attempted used code like this:

[assembly: PreApplicationStartMethod(typeof(Startup), "PreInit")]
namespace Foo
{
  public class Startup {}
}

Where PreApplicationStartMethod is coming from the System.Web namespace. In this case, the call to register areas occurs too early.

The second approach, based on this post by David Ebbo, uses WebActivator: using System.Web.Mvc;

    [assembly: WebActivatorEx.PostApplicationStartMethod
(typeof(AreaDemo.AreaConfig), "RegisterAreas")]
    namespace AreaDemo
    {
        public class AreaConfig
        {
            public static void RegisterAreas()
            {
                AreaRegistration.RegisterAllAreas();
            }
        }
    }

Unfortunately, although there is no error thrown, attempting to navigate to the area fails (as if registration never occurred).

What is the proper way to register areas in ASP.NET MVC 5 from a startup class using an assembly directive rather than a direct call from Global.asax?

Update 1: Here is my AreaRegistration code:

public class AdminAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get
        {
            return "Admin";
        }
    }

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "Admin_default",
            "Admin/{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new string[] { "AreaDemo.Areas.Admin.Controllers" }
            );
    }
}

For some reason the defaults are ignored, but navigating to /admin/home/index/0 works. /admin, /admin/home, and /admin/home/index all 404.

1

There are 1 answers

0
Eilon On

I believe this to be an ordering issue (which it seems you suspect as well). I think that the areas are getting registered after the Application_Start event, and thus the areas' routes are registered after the non-area routes.

The reason that the 4-segment URL (/admin/home/index/123) works is that it can't match the "default" route of the MVC app. So, that default route gets skipped (because it matches only 1-, 2-, and 3-segment URLs), and routing will find the area-specific route that can handle a 4-segment URL. A 1-, 2-, or 3-segment URL will match the non-area route, but of course there are no controllers outside of the areas to handle such a URL, and thus the 404 is returned.

If I understood correctly, you want the areas to be registered after Application_Start, but before anything "else" happens? Unfortunately I'm not aware of any specific event to handle that. From an IHttpModule you could perhaps try handling an event such as BeginRequest, which happens super early, quickly do the registration there only once (that is, don't register stuff on every request!), and that ought to allow you to sneak in before ASP.NET Routing does its stuff (which happens a bit later, during PostResolveRequestCache).

A complete alternative to this is to use attribute routes, which many people like because it can help avoid ordering problems.