Recently I've faced the problem with registering the areas. I added new area to my application, but it didn't seem to work. In this article I'll explain how does the areas registration work under the hood and then how I solved my problem.

How to create areas?

Using Visual Studio it is pretty easy. Just select the project in Solution Explorer, right click and select Add > Area.... The folder structure is created automatically.

Each area has its own class which inherits from AreaRegistration class. The purpose of this class is to register new routes (you add new controllers which will be available using new addresses - the framework has to know about that). In this model each area registers its own routes rather than all routes from all areas are registered in one place.

public class Area1AreaRegistration : AreaRegistration
{
  public override string AreaName
  {
    get { return "Area1"; }
  }

  public override void RegisterArea(AreaRegistrationContext context)
  {
    context.MapRoute(
      "Area1_default",
      "Area1/{controller}/{action}/{id}",
      new { action = "Index", id = UrlParameter.Optional });
  }
}

But shouldn't there be some entry point where areas can plug themselves in? There is. If you open Global.asax you will notice that there is one line of code being automatically added by Visual Studio.

public class MvcApplication : System.Web.HttpApplication
{
  protected void Application_Start()
  {
    AreaRegistration.RegisterAllAreas();
    ...
  }
}

How does RegisterAllAreas work?

Let's look in the source code of AreaRegistration class. For this we will need to use a decompiler. I recommend my favorite dotPeek from JetBrains. It's 100% free and it has the same shortcuts as ReSharper.

The method we are interested in is static RegisterAllAreas (there are three but actually only one does whole job).

  internal static void RegisterAllAreas(
                           RouteCollection routes,
                           IBuildManager buildManager, object state)
  {
    foreach (Type type in TypeCacheUtil.GetFilteredTypesFromAssemblies(
          "MVC-AreaRegistrationTypeCache.xml",
          new Predicate<Type>(AreaRegistration.IsAreaRegistrationType),
          buildManager))
      ((AreaRegistration)Activator.CreateInstance(type))
        .CreateContextAndRegister(routes, state);
  }

It looks like a work it does is pretty straightforward. First of all it uses TypeCacheUtil to find assemblies which contain classes that inherit from AreaRegistration class. The condition is checked in AreaRegistration.IsAreaRegistrationType (you can also notice that the class should have parameterless constructor).

private static bool IsAreaRegistrationType(Type type)
{
  if (typeof (AreaRegistration).IsAssignableFrom(type))
    return type.GetConstructor(Type.EmptyTypes) != (ConstructorInfo) null;
  else
    return false;
}

What is interesting, the classes which are found are stored in MVC-AreaRegistrationTypeCache.xml file. The file is located at c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\NAME_OF_YOUR_APP\\\UserCache\ (source: MVC-ControllerTypeCache.xml in MVC).

The next step of the RegisterAllAreas method is to create an instance of each of these classes and call RegisterArea on them. This is the method that we overriden in our area and registered its routes.

Solving the problem

Let's go back to my initial problem. To remind you: the application wasn't registering routes from my new area. The only suspicious place is the xml file with cached AreaRegistration classes. Caching is very useful when it comes to performance tuning of an application, but in the same way it can bring many problems. It turned out that my new AreaRegistration class wasn't listed there. So I've deleted this file, restarted application and the problem was solved.