Wednesday, December 30, 2009 4:48 PM Kazi Manzur Rashid

ASP.NET MVC 2 and why Dynamic Area is not supported

In my previous post, I mentioned that Area is one of the thing that the coming ASP.NET MVC2 needs heavy enhancements (I also created an Issue in CodePlex). The idea was, Area should have dynamic registering/unregistering support instead of registering all the area at the application start. Recently, I was playing with the Area and trying to find out what are the issues (specially road blocks) for adding such support and it turns out the issue is rather with the ASP.NET Routing instead of the ASP.NET MVC Framework itself.

Before getting down to the main discussion, lets us create a very basic area supported ASP.NET MVC application, lets assume that we have an application which has Blog and Forum as Area and our main Index view has the following code:

<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<ul>
    <li><%= Html.ActionLink("Blog", "Index", "Home", new { area = "Blog" }, null)%></li>
    <li><%= Html.ActionLink("Forum", "Index", "Home", new { area = "Forum" }, null)%></li>
</ul>

Nothing special, just two links which will take you the individual area home. In our global.asax we have the following code:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

If you run the application and click the individual link, it will take you to the corresponding area home as expected. Now, change the code to the following:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    AreaRegistration.RegisterAllAreas();
}

We just swapped the lines, now we are registering the application routes first and then the areas. If you run the application and click any of the links, it will throw “Resource Not Found”. If you recall when the Routing was first introduced, you know that ordering of Route registration is very important and this is exactly what happens here, when we are registering the application route first, the ASP.NET Routing treats the Area Name as Controller Name.

So, if we want to add dynamic area registration we have to make sure that the Routes of Area is registered prior the application routes, so I checked the MapRoute of AreaRegistratonContext if I can make an extension method which inserts the Area Routes at the top instead of appending it at the bottom, we can easily add the support for dynamic area registration. The MapRoute of AreaRegistratonContext internally uses the extension method MapRoute of RouteCollection. The following is the MapRoute extension method:

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
    if (routes == null) {
        throw new ArgumentNullException("routes");
    }
    if (url == null) {
        throw new ArgumentNullException("url");
    }

    Route route = new Route(url, new MvcRouteHandler()) {
        Defaults = new RouteValueDictionary(defaults),
        Constraints = new RouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    };

    if ((namespaces != null) && (namespaces.Length > 0)) {
        route.DataTokens["Namespaces"] = namespaces;
    }

    routes.Add(name, route);

    return route;
}

Check the line 19 which is using the Add with the route name and object. My initial assumption was, since the RouteCollection is Collection type it should have the support for Insert with the name as like as the Add, but it turns out that I am wrong, the RouteCollection does have an Insert but it does not take name as argument and there is no other way to put the name against the route in the RouteCollection. After spending some time with Reflector I find the only important place that it uses the route name is in the non virtual GetVirtualPath method. So if we use the Insert without the name, I think the url generation which depends on the route name will not work. My next try was, what if I created a inherited version of RouteCollection and assign it to the Routes of RouteTable but it does not have any setter, so no luck and could not find any other way to do any kind of monkey patching.

So my request to the ASP.NET Team to add an overloaded version of Insert to RouteCollection which has name as argument in .NET 4.0 and the next service pack for 3.5.

Download : MVCModuleTest.zip

Shout it
Filed under: , , ,

Comments

# Twitter Trackbacks for ASP.NET MVC 2 and why Dynamic Area is not supported - Kazi Manzur Rashid's Blog [asp.net] on Topsy.com

Pingback from  Twitter Trackbacks for                 ASP.NET MVC 2 and why Dynamic Area is not supported - Kazi Manzur Rashid's Blog         [asp.net]        on Topsy.com

# re: ASP.NET MVC 2 and why Dynamic Area is not supported

Wednesday, December 30, 2009 6:53 AM by Yasir Atabani

I agree that the Area needs improvement on ASP.Net MVC 2

# Social comments and analytics for this post

Wednesday, December 30, 2009 6:56 AM by uberVU - social comments

This post was mentioned on Twitter by ManzurRashid: Just blogged: http://tinyurl.com/yzr2xn3 - ASP.NET MVC 2 and why Dynamic Area is not supported #aspnetmvc

# ASP.NET MVC 2 and why Dynamic Area is not supported - Kazi Manzur Rashid

Wednesday, December 30, 2009 8:15 AM by DotNetShoutout

Thank you for submitting this cool story - Trackback from DotNetShoutout

# ASP.NET MVC Archived Buzz, Page 1

Thursday, December 31, 2009 3:37 PM by ASP.NET MVC Archived Buzz, Page 1

Pingback from  ASP.NET MVC Archived Buzz, Page 1

# Fun Events for the New Year | Running Leisure Knowledge

Friday, January 01, 2010 10:30 AM by Fun Events for the New Year | Running Leisure Knowledge

Pingback from  Fun Events for the New Year | Running Leisure Knowledge

# ASP.NET MVC 1.0 Test Driven Development: Problem ??? Design &#8230; | DevBlogr

Pingback from  ASP.NET MVC 1.0 Test Driven Development: Problem ??? Design &#8230; | DevBlogr

# re: ASP.NET MVC 2 and why Dynamic Area is not supported

Friday, January 01, 2010 7:32 PM by Hernan Garcia

This extension does the trick. Adds areas to the top of the collection and adds the name (and the area) to the underlying Dictionary.

The order in the dictionary doesn't seem to be a problem so I'm not changing this.

I'm using reflection heavily so beware of performance issues, also the signature should be changed to present a similar experience as MapRoute.

Feel free to use this code if you find it useful.

       public static RouteCollection AddArea(this RouteCollection routes, string routeName, Route newRoute)

       {

           var fieldInfo =  routes.GetType()

               .GetField("_namedMap", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

           var dict = fieldInfo.GetValue(routes);

           dict.GetType()

               .GetMethod("Add", BindingFlags.Public | BindingFlags.Instance)

               .Invoke(dict,new object[]{routeName,newRoute});

           fieldInfo.SetValue(routes,dict);

           routes.GetType()

               .GetMethod("InsertItem", BindingFlags.NonPublic | BindingFlags.Instance)

               .Invoke(routes, new object[] { 0, newRoute });

           return routes;

       }

# re: ASP.NET MVC 2 and why Dynamic Area is not supported

Friday, January 01, 2010 10:32 PM by simon

That does seem like a good idea, dynamically addable (is that a word?) areas would be very beneficial.  

# For this Minnesota hunting guide, geese hunting still an &#8230; | Minnesota Real Estate

Pingback from  For this Minnesota hunting guide, geese hunting still an &#8230; | Minnesota Real Estate

# re: ASP.NET MVC 2 and why Dynamic Area is not supported

Saturday, January 02, 2010 11:37 AM by Kazi Manzur Rashid

@Hernan : Certainly you can do it with reflection, but I think it will only work in Full Trust which most of application is not going to run.

That is the reason I am asking for a built-in method.

# re: ASP.NET MVC 2 and why Dynamic Area is not supported

Monday, January 04, 2010 2:09 PM by Eilon

Hi Kazi,

Thanks for the feedback on the limitation of the RouteCollection's Insert method. As you know, Routing is not part of MVC so we can't make improvements to it as part of MVC. Routing for ASP.NET 4 is already locked down for this year's release of the .NET Framework.

One thing I'd like to mention about Areas is what we intend them to be. Areas are meant to be a way to divide a large application into smaller areas. It is not meant to be a system to develop "modules" that can be plugged into existing applications and/or loaded/unloaded dynamically, from external assemblies, or other things. We'd love to build something like that, and it's on our list for MVC v3, but it isn't in MVC v2, and it isn't what Areas is meant to be.

Thanks,

Eilon

# re: ASP.NET MVC 2 and why Dynamic Area is not supported

Monday, January 04, 2010 3:13 PM by Kazi Manzur Rashid

Hi Eilon,

Sorry to hear that I guess I am late in reporting the issue ;-).

The Area/Module/Part all are very similar and I am sure a lot of people will try to do the same like myself if they are not fully aware of the actual intention of this feature.

Looking forward for the v3.0 and again nice work on v2.0

# ASP.NET MVC Archived Blog Posts, Page 1

Tuesday, January 05, 2010 12:36 AM by ASP.NET MVC Archived Blog Posts, Page 1

Pingback from  ASP.NET MVC Archived Blog Posts, Page 1

# Area in ASP.NET MVC 2 http://weblogs.asp.net/rashid/archive/2009/12/30/asp-net-mvc-2-and-why-dynamic-area-is-not-supported.aspx

Wednesday, March 31, 2010 12:37 PM by Twitter Mirror

Area in ASP.NET MVC 2 http://weblogs. asp.net /rashid/archive/2009/12/30/asp-net-mvc-2-and-why-dynamic

# ASP.NET MVC 3 RC AreaRegistration.RegisterAllAreas() and dynamically loaded assemblies &middot; Technology Articles

Pingback from  ASP.NET MVC 3 RC AreaRegistration.RegisterAllAreas() and dynamically loaded assemblies &middot; Technology Articles