Best Practices For MVC

Models

Add a class library project to the solution named as Store.Model. This library is where we'll keep all of our domain objects. Entity Framework will count on them in order to build the database but we are not going to configure Code First using DataAnnotations attributes on this project. Instead, we are going to put all the Code First configuration in specific Configuration classes using the Fluent API. Add a folder named Models.

Create a ViewModel for each view

Create a specialized ViewModel for each View. The role of ViewModel should only be data binding. It should not contain any presentation logic.

HtmlHelper

For generating View html, use HtmlHelper. If the current HtmlHelper is not sufficient, extend it using extension methods. This will keep the design in check.

Action Methods

Decorate your action methods with appropriate verbs like Get or Post as applicable.

Caching

Decorate your most used action methods with OutputCache attribute.

Controller and Domain logic

Try to keep away domain logic from controller. Controller should only be responsible for Input validation and sanitization.

Get view related data from the model.

Return the appropriate view or redirect to another appropriate action method.

  • Controller
    Its name must end with “controller” word. Eg. PersonalDetailsController, EmployeesController. Generally all controllers should be kept inside ~/Controllers folder of the project.

  • Model
    Model name (Singular name) corresponding to the database table should be similar to the database table name (not mandatory, however its ideal). For example, if the database table name is "PersonalDetails" (Plural), the model name should be "PersonalDetail" (Singular).

    Generally, all models are kept inside the ~/Models folder of the project.

    • ViewModel
      View model is a class that contains properties from more than one Models, generally used to list data from more than one database tables, read more here. Ideally the name of the ViewModel should end with "ViewModel" word, for example PersonalDetailFileViewModel.
  • Views
    There should be a view folder inside ~/Views folder corresponding to each controller. Like for PersonalDetailsController, there should be a folder ~/Views/PersonalDetails, similarly for EmployeesController, there should be ~/Views/Employees folder.

Areas 

Areas are used to create different modules inside an ASP.NET MVC application. Each module can have their own set of controllers, models and views and the naming conventions of these will follows the same principal as described above.

Areas are functionally independent modules of your ASP.NET MVC application that mimic the folder structure and conventions of MVC

With areas in place, each module replicates the MVC folder structure. For example, each module will have its own Models, Views and Controllers folder.

It is also possible that we can have large projects that use MVC, then we need to split the application into smaller units called areas that isolate the larger MVC application into smaller functional groupings. A MVC application could contain several MVC structures (areas).

Prerequisites

You need to have the following to complete this article,

  • MVC 5
  • Visual Studio 2013
Below are the steps to Add Areas in our Projects

Step 1

Open Visual Studio 2013.

Step 2

Create an ASP.NET Web Application with MVC 5 project template.

Step 3

In Solution Explorer, right-click on the project and click "Add" to add an area as shown below,

ASP.NET Web Application

Step 4

Enter the name for the area, such as "News".

ASP.NET Web Application

Step 5

Similarly add an another area named "Article".

ASP.NET Web Application

Initial Configuration

A lot of Web applications need some initialization code that runs upon startup. This code is usually invoked explicitly from the Application_Start event handler. An interesting convention introduced with ASP.NET MVC 4 is the use of xxxConfig classes. Here’s an example that configures MVC routes, 

  1. public class RouteConfig {  
  2.     public static void RegisterRoutes(RouteCollection routes) {  
  3.         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
  4.         routes.MapRoute(name: "Default", url: "{controller}/{action}/{id}", defaults: new {  
  5.             controller = "Home",  
  6.                 action = "Index",  
  7.                 id = UrlParameter.Optional  
  8.         });  
  9.     }  
  10. }   

The code in global_asax looks like this,

  1. RouteConfig.RegisterRoutes(RouteTable.Routes);  

 

Bundling and Minifying CSS Files

Too many requests from a single HTML page may cause significant delays and affect the overall time-to-last-byte metrics for a site. Bundling is therefore the process of grouping distinct resources such as CSS files into a single downloadable resource. In this way, multiple and logically distinct CSS files can be downloaded through a single HTTP request.

Minification, on the other hand, is the process that removes all unnecessary characters from a text-based resource without altering the expected functionality. Minification involves shortening identifiers, renaming functions, removing comments and white-space characters. In general, minification refers to removing everything that’s been added mostly for readability purposes, including long descriptive member names.

Although bundling and minification can be applied together, they remain independent processes. On a production site, there’s usually no reason not to bundle minified CSS and script files. The only exception is for large and very common resources that might be served through a Content Delivery Network (CDN). The jQuery library is a great example.

Bundling requires the Microsoft ASP.NET Web Optimization Framework available as a Nuget package. Downloading the Optimization Framework also adds a few more references to the project. In particular, they are WebGrease and Microsoft Infrastructure

Bundles are created programmatically during the application startup in global.asax. Also in this case, you can use the xxxConfig pattern and add some BundlesConfig class to the App_Startup folder. The BundleConfig class contains at least one method with code very close to the following snippet. 

  1. public static void RegisterBundles(BundleCollection bundles)  
  2. {  
  3.     bundles.Add(new StyleBundle("~/Content/Styles").Include("~/Content/Styles/bootstrap.css""~/Content/Styles/myapp.css"));  
  4. }   

The code creates a new bundle object for CSS content and populates it with distinct CSS files defined within the project. Note that the Include method refers to physical paths within the project where the source code to bundle is located. The argument passed to the StyleBundle class constructor instead is the public name of the bundle and the URL through which it will be retrieved from pages. There are quite a few ways to indicate the CSS files to bundle. In addition to listing them explicitly, you can use a wildcard expression 

  1. bundles.Add(new Bundle("~/css")  
  2. .Include("~/content/styles/*.css");  

Once CSS bundles are defined invoking them is as easy as using the Styles object

  1. @Styles.Render("~/Bundles/Css")  

 

Bundling and Minifying Script Files

Bundling and minification apply to script files in much the same way as bundling and minifying CSS files. The only minor difference is that for frequently used script files (such as jQuery) you might want to use a CDN for even better performance. In operational terms, bundling and minifying script files requires the same process and logic as CSS files. You use the Bundle class if you’re only concerned about packing multiple files together so that they are captured in a single download and cached on the client. Otherwise, if you also want minifying, you use the ScriptBundle class. 

  1. bundles.Add(new ScriptBundle("~/Bundles/Core").Include("~/Content/Scripts/myapp-1.0.0.js""~/Content/Scripts/knockout-3.0.0.js"));   

The Structure of the _Layout File

In ASP.NET MVC, a layout file is what a master page was in classic Web Forms: the blueprint for multiple pages that are ultimately built out of the provided template. What should you have in a master view? And in which order?

With the exceptions and variations mentioned a moment ago for parallelizing the download of multiple scripts, there are two general rules that hold true for the vast majority of websites. The first rule says: Place all of your CSS in the HEAD element. The second rule says: Place all of your script elements right before the closing tag of the <body> element.

There are a few other little things you want to be careful about in the construction of the layout file(s) for your ASP.NET MVC application. First off, you might want to declare explicitly that the document contains HTML5 markup. You achieve this by having the following markup at the very beginning of the layout and subsequently at the beginning of each derived page.

  1. <!DOCTYPE html>  

 

The DOCTYPE instructs older browsers that don’t support specific parts of HTML5 to behave well and correctly interpret the common parts of HTML while ignoring the newest parts. Also, you might want to declare the character set in the HEAD block.

  1. <meta charset="UTF-8">  

 

The charset attribute is case-insensitive, meaning that you can indicate the character set name as UTF-8, utf-8 or otherwise. In general, you don’t use other character sets than UTF-8, as it’s the default encoding for Web documents since HTML4, which came out back in 1999. As far as IIS and ASP.NET are concerned, you have other ways to set the character set. For example, you can type it in the <globalization> section of the web.config file. Having it right in each page just adds clarity. An interesting consequence of clarifying the character set being used is that you can avoid using HTML entities and type special characters directly in the source. Canonical examples are the copyright (&copy;), trademark (&reg;), euro (&euro), dashes (&mdash;), and more. The only HTML entities you should use are those that provide the text version of reserved markup characters, such as less-than, greater-than, and ampersand.

Another rather important meta-tag you’ll want to have is the viewport meta-tag whose usage dates back to the early days of smartphones. Most mobile browsers can be assumed to have a rendering area that’s much larger than the physical width of the device. This virtual rendering area is just called the "viewport." The real size of the internal viewport is browser-specific.

The viewport meta-tag is a way for you to instruct the browser about the expected size of the viewport. 

  1. <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />   

In this example, you tell the browser to define a viewport that is the same width as the actual device. Furthermore, you specify that the page isn’t initially zoomed and worse, users can’t zoom in.

In ASP.NET MVC, pay a lot of attention to keeping the layout file as thin as possible. This means that you should avoid referencing from the layout file CSS and script files that are referenced by all pages based on the layout. As developers, we certainly find it easier and quicker to reference resources used by most pages right from the layout file. But that only produces extra traffic and extra latency.

In ASP.NET MVC, a layout page consists of sections. A section is an area that derived pages can override. You might want to use this feature to let each page specify CSS and script (and of course markup) that needs be specific. Each layout must contain at least the section for the body. 

  1. <div class="container"> @RenderBody()  
  2.     <hr />  
  3.     <footer> © @DateTime.Now.Year - ASP.NET QuickUp </footer>  
  4. </div>   

The markup above indicates that the entire body of the page replaces @RenderBody. You can define custom sections in a layout file using the following line: @RenderSection("CustomScripts")

The name of the section is unique but arbitrary and you can have as many sections as you need with no significant impact on the rendering performance. You just place a @RenderSection call where you want the derived page to inject ad hoc content. The example above indicates a section where you expect the page to insert custom script blocks. However, there’s nothing that enforces a specific type of content in a section. A section may contain any valid HTML markup. If you want to force users to add, say, script blocks, you can proceed as follows 

  1. <script type="text/javascript">  
  2.     @RenderSection("CustomScripts")  
  3. </script>   

In this case, overridden sections are expected to contain data that fits in the surrounding markup; otherwise, a parsing error will be raised. In a derived page, you override a section like this 

  1. @section CustomScripts {  
  2.     alert("Hello");  
  3. }   

Keep Controllers Thin

ASP.NET MVC is often demonstrated in the context of CRUD applications. CRUD is a very common typology for applications and it’s a very simple typology indeed. For CRUD applications, a fat controller that serves any request directly is sometimes acceptable. When you combine the controller with a repository class for each specific resource you handle, you get good layering and achieve nifty separation of concerns.

It’s essential to note that the Model-View-Controller pattern alone is not a guarantee of clean code and neatly separated layers. The controller simply ensures that any requests are routed to a specific method that’s responsible for creating the conditions for the response to be generated and returned. In itself, an action method on a controller class is the same as a postback event handler in old-fashioned Web Forms applications. It’s more than OK to keep the controller action method tightly coupled to the surrounding HTTP context and access it from within the controller method intrinsic objects such as Session, Server, and Request. A critical design goal is keeping the controller methods as thin as possible. In this way, the controller action methods implement nearly no logic or very simple workflows (hardly more than one IF or two) and there’s no need to test them.

Membership and Identity

To authenticate a user, you need some sort of a membership system that supplies methods to manage the account of a user. Building a membership system means writing the software and the related user interface to create a new account and update or delete existing accounts. It also means writing the software for editing any information associated with an account. Over the years, ASP.NET has offered a few different membership systems.

Historically, the first and still largely used membership system is centered on the Membership static class. The class doesn’t directly contain any logic for any of the methods it exposes. The actual logic for creating and editing accounts is supplied by a provider component that manages an internal data store. You select the membership in the configuration file. ASP.NET comes with a couple of predefined providers that use SQL Server or Active Directory as the persistence layer. Using predefined providers is fine, as it binds you to a predefined storage schema and doesn’t allow any reuse of existing membership tables. For this reason, it’s not unusual that you end up creating your own membership provider.

Defining a custom membership provider is not difficult at all. All you do is derive a new class from MembershipProvider and override all abstract methods. At a minimum, you override a few methods such as ValidateUser, GetUser, CreateUser, and ChangePassword. This is where things usually get a bit annoying.

The original interface of the Membership API is way too complicated with too many methods and too many quirks. People demanded a far simpler membership system. Microsoft first provided the SimpleMembership provider and with Visual Studio 2013, what appears to be the definitive solution: ASP.NET Identity.

In the ASP.NET Identity framework, all of the work is coordinated by the authentication manager. It takes the form of the UserManager<T> class, which basically provides a façade for signing users in and out. 

  1. public class UserManager < T > where T: IUser {:  
  2. }   

The type T identifies the account class to be managed. The IUser interface contains a very minimal definition of the user, limited to ID and name. The ASP.NET Identity API provides the predefined IdentityUser type that implements the IUser interface and adds a few extra properties such as PasswordHash and Roles. In custom applications, you typically derive your own user type inheriting from IdentityUser. It’s important to notice that getting a new class is not required; you can happily work with native IdentityUser if you find its structure appropriate.

User data storage happens via the UserStore<T> class. The user store class implements the IUserStore interface that summarizes the actions allowed on the user store 

  1. public interface IUserStore < T > : where T: IUser {  
  2.     Task CreateAsync(T user);  
  3.     Task DeleteAsync(T user);  
  4.     Task < T > FindByIdAsync(string userId);  
  5.     Task < T > FindByNameAsync(string userName);  
  6.     Task UpdateAsync(T user);  
  7. }   

The controller holds a reference to the authentication identity manager. An instance of the authentication identity manager is injected in the controller. The link between the user store and the data store is established in the ApplicationDbContext class. You’ll find this class defined by the ASP.NET MVC 5 wizard if you enable authentication in the Visual Studio 2013 project template. 

  1. public class ApplicationDbContext: IdentityDbContext < IdentityUser > {  
  2.     public ApplicationDbContext(): base("DefaultConnection") {}  
  3. }   

The base IdentityDbContextclass inherits from DbContextand is dependent on Entity Framework. The class refers to an entry in the web.config file, where the actual connection string is read. The use of Entity Framework Code First makes the structure of the database a secondary point.

Use PRG pattern for data modification

PRG stands for Post-Redirect-Get to avoid the classic browser warning when refreshing a page after post. Whenever you make a POST request, once the request complets do a redirect so that a GET request is fired. In this way when the user refresh the page, the last GET request will be executed rather than the POST thereby avoiding unnecessary usability issue. It can also prevent the initial request being executed twice, thus avoiding possible duplication issues.

Release history
DateVersion
10 December 2007ASP.NET MVC CTP
13 March 2009ASP.NET MVC 1.0
16 December 2009ASP.NET MVC 2 RC
4 February 2010ASP.NET MVC 2 RC 2
10 March 2010ASP.NET MVC 2
6 October 2010ASP.NET MVC 3 Beta
9 November 2010ASP.NET MVC 3 RC
10 December 2010ASP.NET MVC 3 RC 2
13 January 2011ASP.NET MVC 3
20 September 2011ASP.NET MVC 4 Developer Preview
15 February 2012ASP.NET MVC 4 Beta
31 May 2012ASP.NET MVC 4 RC
15 August 2012ASP.NET MVC 4
30 May 2013ASP.NET MVC 4 4.0.30506.0
26 June 2013ASP.NET MVC 5 Preview
23 August 2013ASP.NET MVC 5 RC 1
17 October 2013ASP.NET MVC 5
17 January 2014ASP.NET MVC 5.1
10 February 2014ASP.NET MVC 5.1.1
4 April 2014ASP.NET MVC 5.1.2
22 June 2014ASP.NET MVC 5.1.3
1 July 2014ASP.NET MVC 5.2.0
28 August 2014ASP.NET MVC 5.2.2
9 February 2015ASP.NET MVC 5.2.3
6 November 2014ASP.NET MVC 6.0.0-beta1
18 November 2015ASP.NET MVC 6.0.0-rc1
17 May 2016ASP.NET Core MVC 1.0.0-rc2
12 August 2016ASP.NET Core MVC 1.0.0
17 August 2016ASP.NET Core MVC 1.0.1
17 November 2016ASP.NET Core MVC 1.0.2
18 November 2016ASP.NET Core MVC 1.1.0

Asp.Net MVC1
  1. Released on Mar 13, 2009
  2. Runs on .Net 3.5 and with Visual Studio 2008 & Visual Studio 2008 SP1
  3. MVC Pattern architecture with WebForm Engine
  4. Html Helpers
  5. Ajax helpers
  6. Routing
  7. Unit Testing
Asp.Net MVC2
  1. Released on Mar 10, 2010
  2. Runs on .Net 3.5, 4.0 and with Visual Studio 2008 & 2010
  3. Strongly typed HTML helpers means lambda expression based Html Helpers
  4. Template Helpers
  5. Support for Data Annotations Attribute
  6. Client-side validation
  7. UI helpers with automatic scaffolding & customizable templates
  8. Attribute-based model validation on both client and server
  9. Overriding the HTTP Method Verb including GET, PUT, POST, and DELETE
  10. Areas for partitioning a large applications into modules
  11. Asynchronous controllers
Asp.Net MVC3
  1. Released on Jan 13, 2011
  2. Runs on .Net 4.0 and with Visual Studio 2010
  3. The Razor view engine
  4. Improved Support for Data Annotations
  5. Remote Validation
  6. Compare Attribute
  7. Session less Controller
  8. Child Action Output Caching
  9. Dependency Resolver
  10. Entity Framework Code First support
  11. Partial-page output caching
  12. View Bag dynamic property for passing data from controller to view
  13. Global Action Filters
  14. Better JavaScript support with unobtrusive JavaScript, jQuery Validation, and JSON binding
  15. Use of NuGet to deliver software and manage dependencies throughout the platform
  16. Good Intelligence support for Razor into Visual Studio
Asp.Net MVC4
  1. Released on Aug 15, 2012
  2. Runs on .Net 4.0, 4.5 and with Visual Studio 2010SP1 & Visual Studio 2012
  3. ASP.NET Web API
  4. Enhancements to default project templates
  5. Mobile project template using jQuery Mobile
  6. Display Modes
  7. Task support for Asynchronous Controllers
  8. Bundling and minification
  9. Support for the Windows Azure SDK
Asp.Net MVC5
  1. Released on 17 October 2013
  2. Runs on .Net 4.5, 4.5.1 and with Visual Studio 2013
  3. One Asp.Net
  4. Asp.Net Identity
  5. ASP.NET Scaffolding
  6. Authentication filters - run prior to authorization filters in the ASP.NET MVC pipeline
  7. Bootstrap in the MVC template
  8. ASP.NET Web API2


Similar Articles