Single Project Areas With ASP.NET MVC 2 Preview 1

code, asp.net mvc 0 comments suggest edit

UPDATEThis post is now obsolete. Single project areas are a core part of ASP.NET MVC 2.

Preview 1 of ASP.NET MVC 2 introduces the concept of Areas. Areas provide a means of dividing a large web application into multiple projects, each of which can be developed in relative isolation. The goal of this feature is to help manage complexity when developing a large site by factoring the site into multiple projects, which get combined back into the main site before deployment. Despite the multiple projects, it’s all logically one web application.

One piece of feedback I’ve already heard from several people is that they don’t want to manage multiple projects and simply want areas within  single project as a means of organizing controllers and views much like I had it in my prototype for ASP.NET MVC 1.0.

areas-folder-structure

Well the bad news is that the areas layout I had in that prototype doesn’t work right out of the box. The good news is that it is very easy to enable that scenario. All of the components necessary are in the box, we just need to tweak the installation slightly.

We’ve added a few area specific properties to VirtualPathProviderViewEngine, the base class for our WebFormViewEngine and others. Properties such as AreaViewLocationFormats allow specifying an array of format strings used by the view engines to locate a view. The default format strings for areas doesn’t match the structure that I used before, but it’s not hard for us to tweak things a bit so it does.

The approach I took was to simply create a new view engine that had the area view location formats that I cared about and inserted it first into the view engines collection.

public class SingleProjectAreasViewEngine : WebFormViewEngine {
    public SingleProjectAreasViewEngine() : this(
        new[] {
            "~/Areas/{2}/Views/{1}/{0}.aspx",
            "~/Areas/{2}/Views/{1}/{0}.ascx",
            "~/Areas/{2}/Shared/{0}.aspx",
            "~/Areas/{2}/Shared/{0}.ascx"
        },
        null,
        new[] {
            "~/Areas/{2}/Views/{1}/{0}.master",
            "~/Areas/{2}/Views/Shared/{0}.master",
        }
        ) {
    }

    public SingleProjectAreasViewEngine(
            IEnumerable<string> areaViewLocationFormats, 
            IEnumerable<string> areaPartialViewLocationFormats, 
            IEnumerable<string> areaMasterLocationFormats) : base() {
        this.AreaViewLocationFormats = areaViewLocationFormats.ToArray();
        this.AreaPartialViewLocationFormats = (areaPartialViewLocationFormats ?? 
            areaViewLocationFormats).ToArray();
        this.AreaMasterLocationFormats = areaMasterLocationFormats.ToArray();
    }
}

The constructor of this view engine simply specifies different format strings. Here’s a case where I wish the Framework had a String.Format method that efficiently worked with named formats.

This sample is made slightly more complicated by the fact that I have another constructor that accepts all these formats. That makes it possible to change the formats when registering the view engine if you so choose.

In my web.config file, I then registered this view engine like so:

protected void Application_Start() {
    RegisterRoutes(RouteTable.Routes);
    ViewEngines.Engines.Insert(0, new SingleProjectAreasViewEngine());
}

Note that I’m inserting it first so it takes precedence. I could have cleared the collection and added this as the only one, but I wanted the existing areas format for multi-project solutions to continue to work just in case. It’s really your call.

Now I can register my area routes using a new MapAreaRoute extension method.

public static void RegisterRoutes(RouteCollection routes) {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapAreaRoute("Blogs", "blogs_area", 
        "blog/{controller}/{action}/{id}", 
        new { controller = "Home", action = "Index", id = "" }, 
        new string[] { "SingleProjectAreas.Areas.Blogs.Controllers" });
    
    routes.MapAreaRoute("Forums", 
        "forums_area", 
        "forum/{controller}/{action}/{id}", 
        new { controller = "Home", action = "Index", id = "" }, 
        new string[] { "SingleProjectAreas.Areas.Forums.Controllers" });
    
    routes.MapAreaRoute("Main", "default_route", 
        "{controller}/{action}/{id}", 
        new { controller = "Home", action = "Index", id = "" }, 
        new string[] { "SingleProjectAreas.Controllers" });
}

And I’m good to go. Notice that I no longer have a default route. Instead, I mapped an area named “Main” to serve as the “main” project. The Route URL pattern there is what you’d typically see in the default template.

If you prefer this approach or would like to see both approaches supported, let me know. We are looking at having the single project approach supported out of the box as a possibility for Preview 2.

If you want to see this in action, download the following sample.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

8 responses

  1. Avatar for Pita.O
    Pita.O July 31st, 2009

    Phil,
    What can I say?! Thank you, again. This is great news. Am not sure if anyone has thought about how these projects (areas) will manage security across their boundaries ... like session or authentication tokens: for instance, are areas also authorization boundaries, do user have to reauthenticate on crossing area boundaries, do child areas inherit token from the parent, etc. Is this configurable behavior? I like configurable.

  2. Avatar for Duncan Godwin
    Duncan Godwin July 31st, 2009

    My first reaction when I heard about areas being for multiple projects was that I would want this to work in single projects as well. This is partly driven by a desire to have as few a projects in a solution as possible because it makes it easier to move things around.
    So, for me I would like to see this in the box for MVC 2.

  3. Avatar for Insomniak
    Insomniak December 23rd, 2009

    Hi Phil,
    Thanks for all your job !
    The code sample at the end of your post is broken.

  4. Avatar for Jim Ralph
    Jim Ralph December 31st, 2009

    Thanks for this. Your sample "zip" is invalid, though, which is frustrating, and your contact page is broken. however, with your hard drive crashes I imagine that is the least of your worries. Good luck! When you might be able to get the code sample back on line, that would be a great boon.

  5. Avatar for Sunil
    Sunil January 7th, 2010

    Hey phil,
    your logic look cool, It will great if you could upload example prototype to acheive areas in MVC1.0
    Thanks
    Sunil

  6. Avatar for notebook adapt&#246;r
    notebook adapt&#246;r February 10th, 2010

    Hi Phil,
    Thanks for all your job !

  7. Avatar for mousedoc
    mousedoc April 14th, 2010

    Removing multi-project areas was a huge step backwards for team development.

  8. Avatar for Rodrigo Caballero
    Rodrigo Caballero October 17th, 2010

    Hi Phil, I tried to make work the multiproject areas from msdn at
    msdn.microsoft.com/.../ee307987%28VS.100%29.aspx
    and after one hour of searching why it wasn't working I realized that multiple project areas are no longer supported on the official ASP.NET MVC 2 release.
    Can you tell me why it is not supported? and, Are there any way or guide to make a more robust architecture based on MVC?
    regards