Area in MVC - Giving a Nice Physical Structure & Dealing With Template Bug

Introduction

As you know, the MVC Architecture separates all the logic: model logic, business logic and presentation logic and provides a very clean and lightweight application in total. One more good thing that I love is, it provides both logical and physical separation. In the physical logic separation, the controllers, models and views are kept in another folder from the root using Area. Areas provide a way to separate a large MVC Web Application into smaller functional groupings in the MVC Application and each group contains a MVC Structure (for example, Model, View and Controller folders). Area was introduced with MVC2 release.

Now, let's talk about a requirement

Assume, you are working on a MVC Project where you must work on an account section, administrative section, support section, billing section and so on. In this case you should use an Area that will provide a strong physical structure. See how it looks like.

MVC1.jpg

You will see that every section has a MVC Architecture Controller, Model and View (the view will have a shared folder where you can place your layouts, partial views etc.) and an AreaRegistration (that contains a RegisterArea method similar to RegisterRoutes).

How to Create It

Here I'm going to create CRUD views for Students inside Area. I get the benefit of EF Code First, let's walk through the simple steps.

Step 1

Right-click on the project and then pick "Add" | "Area".

MVC2.jpg

Step 2

Now this will bring up a dialog-box. Type the area name that is similar to the section name (you will see it in the first image, Admin, Billing, Support).

MVC3.jpg

I typed "Student", then hit the "Add" button.

Step 3

You will see the following structure:

MVC4.jpg

Step 4

As I said, I am using EF Code First so I need a model class, here it is.

  1. public class StudentViewModel  
  2. {  
  3.     public int Id { getset; }  
  4.     public string FirstName { getset; }  
  5.     public string LastName { getset; }  
  6.     public string Address { getset; }  
  7. }   

Step 5

In this step I will name the controller "Student" and in the template select "MVC controller with read/write actions and views, using Entity Framework". Also, select the model class (Student) and then create a new DbContext with the name StudentContext, finish by clicking on the "Add" button.

MVC5.jpg

In the next step we will run the application but before this you should check this entry in the Global.asax file, it should be there on the top.

  1. protected void Application_Start()  
  2. {  
  3.     AreaRegistration.RegisterAllAreas();  
  4.     WebApiConfig.Register(GlobalConfiguration.Configuration);  
  5.     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
  6.     RouteConfig.RegisterRoutes(RouteTable.Routes);  
  7.     BundleConfig.RegisterBundles(BundleTable.Bundles);  
  8.     AuthConfig.RegisterAuth();  
  9. }   

Step 6

Now we are all set to run the project and I expect your app should run, if not don't throw bricks at me.

Well, in my case I encountered an error. I noticed the following nice bug (because I love bugs) in the product template (I will solve this error in Step 7, just keep reading):

An error occurred creating the configuration section handler for system.web.webPages.razor/host: The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)

MVC6.jpg

Notice in the above image I'm trying to navigate to http://localhost:33103/Student/Student. In this URL, the first "Student" segment is my area name and the second "Student" segment is my controller name.

Why am I passing the controller name and can we make it the default?

Keep reading, you will get your answers.

Let's open StudentAreaRegistration.cs (find this file in the "Student" area) file.

MVC7.jpg

Open this file and look at the code.

  1. public override void RegisterArea(AreaRegistrationContext context)  
  2. {  
  3.         context.MapRoute(  
  4.             "Student_default",  
  5.             "Student/{controller}/{action}/{id}",  
  6.             new { action = "Index", id = UrlParameter.Optional }  
  7.         );  
  8. }   

You can see I am registering a new area and in the route we have the following URL format:

"Student/{controller}/{action}/{id}"

Notice the following things:

  1. Controller is preceded by "Student" which is the area name.

  2. In RegisterArea above we have a default value for the action and id is optional.

  3. We don't have a default value for the controller.

If you want to provide a default controller name, do it this way.

  1. public override void RegisterArea(AreaRegistrationContext context)  
  2. {  
  3.         context.MapRoute(  
  4.             "Student_default",  
  5.             "Student/{controller}/{action}/{id}",  
  6.             new { controller = "Student", action = "Index", id = UrlParameter.Optional }  
  7.         );  
  8. }   

Now, only hitting the http://localhost:33103/Student URL will work, because we hardcoded the controller value.

Step 7 

I figured out the issues that we experienced in Step 6. When I opened the Web.config file in "Areas|Student|Views|Web.config", I found some really strange entries for WebPageVersion and MvcVersion. I will call this MVC Template bug which is in product.

MVC8.jpg

And here is the workaround:

  1. Find "__WebPagesVersion__.0.0" and replace it with "2.0.0.0".

  2. Find "__MvcVersion__.0.0" and replace it with "4.0.0.0".

Do a build and try running.

MVC9.jpg 

Yah! It is running now and the only thing left is its presentation layout.

Step 8

To apply a layout, I'll simply copy the _ViewStart.cshtml file, look at the image.

[Tip: To copy it, drag the file while pressing the Ctrl Key in the Solution Explorer]

MVC10.jpg

Now, try running and enjoy.

MVC11.jpg

Hope this helps.


Similar Articles