While reading the book “Dependency Injection in .NET“, I had made a mental note that I would want to revisit the architecture of his sample ASP.NET MVC application (pgs 53-54). Most of us are familiar with the 3 layer architecture:
– User Interface Layer
– Domain Logic Layer
– Data Access Layer
What Mark Seemann proposes is creating a new layer, called “Presentation Model Layer” and sliding it in between the “User Interface Layer” and the “Domain Logic Layer” to end up with the “User Interface Layer” being what is known as a “Humble Object“. The essence of this architecture is that it allows us to have the “Views” in MVC in its own project and moving the “Controllers” and “Models” into the “Presentation Model Layer”. Hence, it makes that logical separation that much clearer i.e. only UI code will be in the UI layer and no or minimal logic or C# code should be in that layer.
So while researching how to do this, I came across this post by Jimmy Bogard. He goes one tiny step further than Mark Seeman and actually puts the “Global.asax.cs” file in the “Presentation Model Layer” (“Core” in his blog post).
This post will demonstrate how I did this and I’ll push the boat out a tiny bit further by also talking about using “Razor Generator“. This will however mean that I’ll get C# code in the UI layer but since this is generated and will not be unit tested, I can live with that. It is possible to have this code in a separate layer but I think it just makes more work for no real gain.
Creating the solution and projects
I start off by creating a blank solution “SeparateViewProjectAndRazorGenerator”.
and then I’ll add an Internet ASP.NET MVC 4 aplication, “UserInterfaceLayer” to that solution.
At this point should you decide to run the web application, you’ll get the default web application
So far this should be pretty straightforward and familiar.
Moving code to Presentation Model Layer
For this I’m making use of ReSharper’s move tool (Ctrl R +O) because it will take care of renaming namespaces. Should ReSharper not be available then it will just mean more manual work but the task should by no means be impossible without it.
First I’ll create a class library “PresentationModelLayer” and add it to the solution.
Then I’ll select the “App_Start”, “Controllers”, “Filters” and “Models” folder and using ReSharper’s move tool (Ctrl R +O), move the folders to the “PresentationModelLayer” project.
ReSharper will warn you that performing this operation might cause problems because the project we’re moving to doesn’t contain references to the code that we are moving requires. Ignore that warning and go ahead.
After the code has been moved, the solution will no longer compile because of the missing references. Simply use ReSharper to add those missing references (Alt + Enter). One step that you will have to do in order the Views in the Controllers to be “recognised” is to reference the “PresentationModelLayer” in the “UserInterfaceLayer” project.
Unfortunately, this is not as easy as moving the folders but it’s not that difficult either. What you’ll have to do is to go use something like “Windows explorer” and move the “Global.asax.cs” file to the “PresentationModelLayer”.
You will have to ensure that “Show all files” is turned on in Visual Studio and include “Global.asax.cs” in the project. You’ll also want to change the namespace of that file. If the “Global.asax.cs” is still showing up in the “UserInterfaceLayer” in Visual Studio, then simply remove the former.
As soon as this is done, you should now be able to compile and run the solution without any issues.
Add Razor Generator
The instructions are based upon this post and what I have below is simply a condensed version.
- Install the Razor Generator Visual Studio add in and you might need to restart Visual Studio at this point.
- In “Package Manager Console” enter “Install-Package RazorGenerator.Mvc” ensuring that the “UserInterfaceLayer” is selected.
Then say you want to precompile “\SeparateViewProjectAndRazorGenerator\UserInterfaceLayer\Views\Home\Index.cshtml”, set its “Custom Tool” property to “RazorGenerator”
This was a bit of a whildwind tour of how I’ve set up my ASP.NET MVC 4 solution but it should get you started onto the road to writing better architected software. Should you be interested in the source code you can find it here.
One drawback to this architecture is the fact that we can’t make use of code scaffolding. This can be mitigated by using an empty ASP.NET MVC project for the “PresentationModelLayer” project but you will still need to move the scaffolded Views to the “UserInterfaceLayer” project.
If you do that however, please be warned that you might get into trouble if you’re deploying to AppHarbor because it will deploy two websites and your site won’t display properly.