Asp.Net MVC3 Areas as Separate Projects

For those of us building large applications with multiple teams it is nice to be able to separate a solution into multiple projects and modularize it. Asp.Net MVC3 does have a built in way to separate out sections of your project using a feature called "Areas."

To create an "Area" in the MVC3 app there is a template. You right click on the solution and choose Add -> Area. A dialog comes up to allow you to name the area. Once you are done the template will create the Area in an "Areas" folder in the MVC project. If you don't already have an Areas folder it will be added. If you already have other areas a new area will be added to the areas folder. Each area has its on Model, Views and Controllers folder. Each area can have its own layout, etc.

However, I wanted to separate out the areas into separate projects so we can have separate teams working on them and also only deploy the areas a users licenses for their system.

It turns out, after some trial and error that this is pretty easy to do.

Let's assume you have a single MVC application project and this will be your "shell" app. Now you want to create your first Area project. Here are the basic steps:

  1. Right click on the shell project and "Add Area...". Type in the area name. This will create an Areas folder with your area in it. (This is not 100% needed but you do need the "Areas" folder and you can steal the XXXXAreaRegistration class for your application.)

  2. Create a new MVC3 empty project in your solution to match your area. Move the XXXXAreaRegistration.cs file from the shell mvc project to the new project and adjust the namespace as applicable. (Or you can manually create an area registration class, it's a pretty simple class. Just use the Add area template generated one as an example.)

  3. Edit the routes in the AreaRegistration folder as needed.

  4. Delete the folder under the areas folder that the template wizard added.

  5. Modify the web.config of the new project and take out the connection strings and the authentication, membership, profile, rolemanger sections. You will not need to deploy this web.config but the razor intellisense doesn't work without it during dev time.

  6. Delete the global.asax file from the area's project or you will get extra default routes.

  7. Create a virtual directory in the "Areas" folder of the shell project with the name of your area as the alias and point it to your "area" project. You will need to use IIS or IIS Express for this. I use IIS. For IIS Express you can use the appcmd.exe in the IIS Express folder or you can edit the applciationhost.config file.

That's about it. However, there is one other step... you need to get the dll and any projects that it references into the shell projects bin folder during build. There are two ways you can do this:

  1. Reference the area project from the shell project. This is the simplest way to do it and it ensures the area projects as well as anything they reference are brought in automatically.

  2. Modify the output folder on the area projects to build into the shell's bin folder. I would use this method if it weren't for what I consider a bug in Visual Studio 2010. For some reason it expects binaries for namespaces in the views/web.config file to be in the GAC or in a bin folder directly under the project folder. So, for third party extensions like DevExpress's or Teleriks you will get reference issues and intellisense won't work.

  3. Create a post-build event on your "area" project to copy the build dll and references dlls to the "shell" projects bin folder. An example build event is: copy $(TargetDir)* $(SolutionDir)\ShellProjectName\bin . This turns out to be the best method and the one I am using due to the issues with method 1 and the bug in VS that method 2 exposes.

It turns out that is all you need to do. MVC3 uses the BuildManager class to find all references of the AreaRegistration class in all the assemblies in the bin folder. So, even though you never specify a reference in the shell project or its web confing MVC will still find your area registration classes and load the routes. You can verify it is working by using Phil Hacks routeDebugger which you can load usin NuGet.

Well, that's it... happy oranizing to you all. Let's hope my next blog entry doesn't take another year.

Comments

Having Issues with finding the Views

I am doing something wrong in Step 7 (using IIS Express.) I keep getting an error saying that it cannot find the views (my test area is called "Sample") Here is the error:

The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:

    ~/Areas/Sample/Views/Index/Index.aspx<br />
    ~/Areas/Sample/Views/Index/Index.ascx<br />
    ~/Areas/Sample/Views/Shared/Index.aspx<br />
    ~/Areas/Sample/Views/Shared/Index.ascx<br />
    ~/Views/Index/Index.aspx<br />
    ~/Views/Index/Index.ascx<br />
    ~/Views/Shared/Index.aspx<br />
    ~/Views/Shared/Index.ascx<br />
    ~/Areas/Sample/Views/Index/Index.cshtml<br />
    ~/Areas/Sample/Views/Index/Index.vbhtml<br />
    ~/Areas/Sample/Views/Shared/Index.cshtml<br />
    ~/Areas/Sample/Views/Shared/Index.vbhtml<br />
    ~/Views/Index/Index.cshtml<br />
    ~/Views/Index/Index.vbhtml<br />
    ~/Views/Shared/Index.cshtml<br />
    ~/Views/Shared/Index.vbhtml

My IIS Express applicationhost.config is set up this way:

        <site name="Vo.MainSite" id="5">
            <application path="/" applicationPool="Clr4IntegratedAppPool">
                <virtualDirectory path="/" physicalPath="D:\{LONG PATH}\MainSite\MainSite\MainSite" />
            </application>
            <application path="/Areas/Sample" applicationPool="Clr4IntegratedAppPool">
                <virtualDirectory path="/" physicalPath="D:\{LONG PATH}\Modules\SampleModule\SampleModule.Web" />
            </application>
            <bindings>
                <binding protocol="http" bindingInformation="*:47001:localhost" />
            </bindings>
        </site>

Which, from everything I am googling, it should be correct. I have the post build process copying the DLL just fine. I can put a breakpoint in the SampleController and the breakpoint gets hit. Everything looks good, except finding the views. Any suggestions?

And a note for the person who was asking about debugging: you need to set your solution up to debug both projects at once. Right-click on the solution file > Properties > Startup Project > Multiple Startup Projects and then choose your projects.

Are you sure you don't have

Are you sure you don't have to set the Virtual Directory path?

Unable to debug my individual area projects with breakpoints.

Hi, I have followed all your steps and everything is fine. But when I am running the individual area projects I am unable to debug (Unable to debug my code even i used breakpoints, I can debug only the parent projects which has the Areas folder). Can you help me in sorting out this problem.

Regards, Suresh.

I don't recall having any

I don't recall having any issues debugging, however, I'm not sure if I did any debuging either. The Visual Studio tooling really doesn't like it set up this way.... so there will be some caveats on using it.

Without creating virtual directory

Hi,

I have achieved what you said by creating virtual directory. But I want to achieve this (areas as multiple projects) with out creating a virtual directory. I hope they can be achived with the last 3 steps available in the article. But I am unable to understand them clearly, so can you please explain in more detail about the last step (copying references and dlls in to shell project). I will be grateful to you if you do this favor.

Thanks in Advance, Suresh.

Sorry, you will still need

Sorry, you will still need the virtual directory otherwise the views won't be fond. Of course, this is only needed in development. In deployment you will just copy the modules into the areas folder of your root application and be good to go.