MVC

,Model-View-Control Architectural Pattern

Web page by Kevin Harris of Homer IL

Please contact Kevin Harris of Homer IL concerning this web site

Model-View-Controller

The "Model-View-Controller (MVC)" is a design pattern created by Trygve M. H. Reenskaug in 1978. Reenskaug made the first implementation and wrote the original MVC note while working as a visiting scientist at the Xerox Palo Alto Research Center (PARC). Many individuals contributed to the evolution of MVC before it was adopted as an ASP.NET web application framework in 2007. Other popular web application frameworks which are based on MVC include: Ruby on Rails, JavaServer Pages, Django (Python), and Apache Struts (Java).


ASP.NET first released with .NET 1.0 in early 2002. At that time Microsoft was trying to bring web development to two types of Microsoft developers: the classic ASP developers and the Desktop Line of Business (LOB) developers (the VB6 and WinForms developers). Combining the aspects of those two types of developers (HTTP intrinsics, Event Handlers, Session, Controls) resulted in the monolithic Web Forms framework wrapped up into a single assembly (System.Web). The monolithic nature of the We bForms framework slowed the shipping cycles, while the pace of the changes in web technology were increasing. The increasing functionality, and size, of System.Web had a negative impact on performance. Web Forms also defaulted to have most options turned on by default. So developers had to "opt-out" to turn off features they did not need ... which they did not always do. Running unneeded features also had a negative impact on performance.

In 2007 Scott Guthrie announced and demonstrated the new ASP.NET MVC framework at the first ALT.NET conference. The MVC design pattern dates back to 1978 and Xerox PARC. In 2007 Microsoft was facing competition from Ruby on Rails and other platforms who were successfully implementing a modern variant of MVC. In 2007 Microsoft decides that MVC will ship "out of band" from the .NET framework which allows for more frequent updates to be released (via NuGet). This resulted in a major release of MVC every year since 2009.

So ASP.NET MVC was released as an additional web application framework to the existing Web Forms framework. The Web Forms framework was designed to abstract web development into an environment already familiar to desktop developers. Web Forms provided a Rapid Application Development environment with an event-driven lifecycle, server controls, and built-in state management ... which provided a familiar environment for developers of Windows applications.

However, the ASP.NET MVC framework works more closely to the actual underlying HTTP environment of the Internet. Without the abstracts present in Web Forms, MVC allows for the development of more flexible, and more testable, web applications. ASP.NET has evolved quickly with MVC 5 as the current production release. MVC 6 is in preview mode as part of vNext and contains significant changes to coincide with vNext's "host agnostic" framework.

MVC Releases
Version Capabilities
MVC V1 (2009) Entity Framework ORM. Visual Studio 2008.
MVC V2 (2010) Web Forms view engine syntax (.aspx). Master Pages. VS 2008 & 2010.
MVC V3 (2011) Razor View engine syntax (.cshtml). Layout Pages. VS 2010
MVC V4 (2012) ViewBag added to allow dynamic properties. Features for mobile apps & Azure. VS 2010 & 2012
MVC V5 (2013) Scaffolding. VS 2013
MVC V6 (2015) Still in preview mode as of Janary 2016.


MVC  vs  Web Forms

Web Forms abstracted away the stateless nature of the HTTP protocol with built in mechanisms for storing state. Web Forms provided Server Controls which could be dragged-and-dropped onto the design surface. The Server controls were processed on the server to return HTML. Automatically maintaining state and having the server generate HTML make development similar to the development of desktop programs. However it consumed a lot of bandwidth and resulted in slower response times. MVC provides better performance, and scalability, by having the developer create the HTML, and eliminating the server call required by Server Controls to generate the HTML (i.e. MVC does not use Server Controls). Also MVC is stateless by default, so it does not send the potentially large amounts of View State as did Web Forms.

While MVC offers better performance and scalability that Web Forms, MVC requires the programmer to do more work in coding the HTML and related JavaScript on the client side. MVC has a steeper learning curve than Web Forms and requires more time to develop. Web Forms is a Rapid Application Development environment. Both Web Forms and MVC are fully supported ASP.NET frameworks which provide two different methods for developing web applications. Many of the newer areas of web development (such as web API) use, or built off of, the MVC framework.

.Web Forms View State


Web Forms - Large Amounts of View State sent on Response from Server

Below is a list of the differences between MVC and Web Forms.

Web Forms

  1. Rapid Application Development environment. Visual tools with drag-and-drop designer.
  2. Familiar environment for desktop developers
  3. Abstracts the stateless nature of the web with built in state mechanisms (e.g. View State) and events.
  4. Uses Server Controls to generate HTML for screen elements (consuming more server side processing and requiring a server request).
  5. Can consume large amounts of bandwidth because of its use of View State.



MVC

  1. Architecture reflects the stateless nature of the HTTP protocol
  2. A more familiar environment for web developers who are use to other web frameworks.
  3. Requires more development by programmer. More coding with HTML, JavaScript, and jQuery.
  4. Code HTML directly, or use HTML helper methods for creating screen elements (No server controls).
  5. Is stateless by default, so uses less bandwidth.
  6. Components are loosely coupled, making maintenance and automated testing easier.

MVC Overview


  • Models - Classes that represent the data of the application and that use validation logic to enforce business rules for that data.

  • Views - Template files that your application uses to dynamically generate HTML responses.

  • Controllers - Classes that handle incoming browser requests, retrieve model data, and then specify view templates that return a response to the browser.

A common MVC process starts with a user initiating a request (e.g. clicking a button or submitting a form). The request takes the form of a URL (e.g. http://host//Controller/ActionMethod) and is routed to a controller and an action method for processing. The action method in the controller typically accesses the model to obtain data. The data in the model could come from various sources, such as a database or files. The controller then passes this data to a View which formats the data for display on the user's screen.

Route maps (route.MapRoute) are specified which control how the URL is directed to the controller and action method. Early versions of MVC had the route mapping in the Global.asax, but starting with MVC 4 the default location for the route map was broken out to RouteConfig.cs in the App_Start folder. The RouteConfig.cs is called from the Application_Start() method in the Global.asax. Along with the route maps, MVC requires certain naming conventions and locations for various components.

MVC follows the rule of Convention over Configuration which means it depends on naming conventions and locations of components over specifying associations in configuration files. For example, a controller must be named with the word controlleras the last part of the name (i.e. AbcController.cs). Then the names of Action Methods in the controller which correspond to a view, will have the view named the same as the action method. These views are located inside a subdirectory named after the controller, inside the Views directory. So if the HomeController.cs has an action method named Index() which returns a view. Then the view is called Index.cshtml and is stored in the Home subdirectory inside the Views folder.

Action Methods are public method inside a controller which accepts user requests and returns a response. In Web Forms, user interaction centers around pages, and with raising and handling events from the page and from controls on the page. In MVC, user interaction centers around action methods. User interactions (like clicking a link, or submitting a form) invoke action methods which causes a request to be sent to the server. Action Methods must be public, they cannot be overloaded or static. Action methods typically return an appropriate Action Result Class type, as listed below.

Action methods are decorated with attributes:

  1. ActionName - specifies a different action name than the method name. [ActionName("FindCustomer")]
  2. NonAction - indicates a public method is not an action method [NonAction]
  3. ActionVerbs control the selection of the action method based on the Http request method. You can define two action methods with the same name, but one responds to the Get Http request while the other responds to the Post Http request. The ActionVerb defaults to GET [HttpGet]. Others include:
    1. [HttpPost]
    2. [HttpPut]
    3. [HttpDelete]
    4. [HttpHead]
    5. [HttpOptions]
    6. [HttpPatch]

Most action methods returns an instance of a class that derived from ActionResult. Various ActionResult types exist corresponding to the task to the task of the action method.

Action Result

Helper Method

Description

ViewResult

View

Renders a view as a Web page.

PartialViewResult

PartialView

Renders a partial view, which defines a section of a view that can be rendered inside another view.

RedirectResult

Redirect

Redirects to another action method by using its URL.

RedirectToRouteResult

RedirectToAction

RedirectToRoute

Redirects to another action method.

ContentResult

Content

Returns a user-defined content type.

JsonResult

Json

Returns a serialized JSON object.

JavaScriptResult

JavaScript

Returns a script that can be executed on the client.

FileResult

File

Returns binary output to write to the response.

EmptyResult

(None)

Represents a return value that is used if the action method must return a null result (void).

HttpUnauthorizedResult Return HTTP 403 Status
FileContentResult/FilePathResult/FileStreamResult Represents the content of a file


Views

Microsoft's first server-side scripting engine for dynamically generating web pages (now called Classic ASP, circa 1996) combined a server-side scripting language (VBScript, JScript, PerlScript) inside a file (.asp) along with HTML code. The scripting code was placed between <% and %> tags to delimit the code for the server-side interpreter. The server would use the interpreter to execute the code and combine the results with the HTML from the .asp file. The combined results consisted of pure HTML which was returned to the browser for display.

In 2002, Microsoft released a replacement for ASP (called ASP.NET, now referred to as Web Forms) which replaced the scripting languages with compiled .NET languages, mixed with HTML, inside an .aspx file. The .NET code was placed between <% and %> tags to delimit the code for the compiler. The compiler translated the .NET code into intermediate code (Microsoft Intermediate Language, MSIL) which was executed in the context of the .NET Framework. Once again the code and HTML were mixed in one file, processed by the server, and returned as pure HTML for the browser to display.

As part of .NET 2.0 (circa 2005), Microsoft introduced a Code-behind model which moved the code to another file (the code-behind file, .aspxcs/.aspxvb). The code-behind contained a partial class which tied the HTML and code together while keeping them in separate files. .NET 2.0 also supported the use of embedded code blocks within the .aspx file, primarily to preserve backward compatibility with older ASP technology. With the Code-behind model, Microsoft was establishing a best practice for developers to separate the HTML from the code. Also released in .NET 2.0 were Master Pages, which provided a common underlying display template to be used with multiple pages.

When Microsoft introduced it's version of the MVC architecural pattern in 2009, is used the .aspx engine for creating the views and still used Master Pages. When MVC 2.0 was released in 2011, in contained a new Razor engine for creating the views (.cshtml/.vbhtml) and replaced the Master Pages with Layout Pages. However the best practice of keeping the HTML and code separate remained. This was encouraged in MVC by the use of View Models. In MVC, Models are used to store the business data, while View Models are used to store the data required to support a particular view. Controllers may use data from several Models to create a View Model. So the server-code should reside in the Controller, while the HTML should reside in the View.

Razor View Engine

- razor is similar to the old Response.Write, except by default razor html encodes the text to help prevent cross-site scripting attacks.
If you wish to not html encode the text, use "@Html.Raw()

- Implicit expression example showing text "/ 5"
@item.Cost / 5

- Explicit expression example, dividing cost by 5 and showing the results
@(item.Cost / 5)

D@item.Cost is displayed as "D@item.Cost" (thinks it is an email address because of embedded @)
D@(item.Cost) is displayed as "D5" (if item.Cost = 25)

To display something with leading @ sign, use two @ signs
@@Kevin would display "@Kevin"

Code Blocks - executes the code inside the block and outputs the result.

Razor support code blocks
@{
var firstItem = Model.First();
}

@firstItem.Description

@foreach (var item in Model) {

item.Description

item.Cost

}
also creates a code block.

Use @: to specify literal text inside a code block.

Layout View similar to Master Pages
RenderBody (Required)
RenderSection (Optional)

Passing Data from Controllers to Views

.Output of Views


ViewData, ViewBag, Strongly Typed View, View Model

  1. ViewData - ViewData is a dictionary object which is used to pass data between a controller and views. Controllers add items to the dictionary and the view reads the items from the dictionary. ViewData is derived from the ViewDataDictionary class and contains "key/value" syntax for storing items. ViewData requires typecasting (unboxing) for complex data type and check for null values to avoid error.
  2. ViewBag - ViewBag is a wrapper around the ViewData object. ViewBag uses the dynamic feature of C# 4.0 which allows for the creation of dynamic properties. The ViewBag syntax uses properties (e.g. ViewBag.Foo), while ViewData uses the string syntax (e.g. ViewBag["foo"]). ViewBag doesn’t require typecasting for complex data type.
  3. Strongly Typed Views - In stead of using ViewData or ViewBag, a Strongly Typed View associates a view with a model. This allows for strong compiler-time type checking (instead of getting run time errors on type mismatches). Strongly Typed Views also provides the information which allows intellisense to prompt for all the properties in the model.
  4. ViewModels - ViewModels define the data required for a particular view. The controller creates the ViewModel object based on one or more Model objects. It is best practices for every view have its own ViewModel.
1
2
3
4
5
6
7
8
9
namespace MVC1.Models
{
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public double PurchaseAmount { get; set; }
    }
}


Customer Model

1
2
3
4
5
6
7
8
namespace MVC1.Models
{
    public class Salesman
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}


Salesman Model

1
2
3
4
5
6
7
8
9
namespace MVC1.ViewModels
{
    public class PurchaseViewModel
    {
        public string CustomerName { get; set; }
        public double PurchaseAmount { get; set; }
        public string SalesmanName { get; set; }
    }
}


Purchase ViewModel

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System.Web.Mvc;
using MVC1.Models;
using MVC1.ViewModels;

namespace MVC1.Controllers
{
    public class TestController : Controller
    {
        private Customer theCustomer { get; set; }
        public Salesman theSalesman { get; set; }

        public TestController()
        {
            Customer cust = new Customer();
            cust.FirstName = "Kevin";
            cust.LastName = "Harris";
            cust.PurchaseAmount = 12.95;
            theCustomer = cust;

            Salesman sman = new Salesman();
            sman.FirstName = "Fred";
            sman.LastName = "Smith";
            theSalesman = sman;
        }

        //View Data
        public ActionResult GetView1()
        {
            ViewData["Customer"] = theCustomer;
            return View("View1");
        }

        // View Bag
        public ActionResult GetView2()
        {
            ViewBag.Customer = theCustomer;
            return View("View2");
        }

        // Strongly Typed View
        public ActionResult GetView3()
        {
            return View("View3", theCustomer);
        }

        // View Model
        public ActionResult GetView4()
        {
            PurchaseViewModel vmPurchase = new PurchaseViewModel();
            vmPurchase.CustomerName = theCustomer.FirstName + " " +  theCustomer.LastName;
            vmPurchase.PurchaseAmount = theCustomer.PurchaseAmount;
            vmPurchase.SalesmanName = theSalesman.FirstName + " " + theSalesman.LastName;
            return View("View4", vmPurchase);
        }

    }
}


Test Controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@*This View gets data through ViewData*@

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>View 1</title>
</head>
<body>
    <div>
        @{
            MVC1.Models.Customer cust = (MVC1.Models.Customer)ViewData["Customer"];
        }
        <b>This View gets data through ViewData</b> <br /><br />

        <u>Customer Details</u><br />
        Customer Name : @cust.FirstName @cust.LastName<br />
        Purchase Amount: @cust.PurchaseAmount.ToString("C")
    </div>
</body>
</html>


View 1 (ViewData)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@*This View gets data through ViewBag*@

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>View 2</title>
</head>
<body>
    <div>
        @{
            MVC1.Models.Customer cust = (MVC1.Models.Customer)ViewBag.Customer;
        }
        <b>This View gets data through ViewBag</b> <br /><br />

        <u>Customer Details</u><br />
        Customer Name : @cust.FirstName @cust.LastName<br />
        Purchase Amount: @cust.PurchaseAmount.ToString("C")
    </div>
</body>
</html>


View 2 (View Bag)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@*This is a Strongly Typed View*@

@model MVC1.Models.Customer

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>View 3</title>
</head>
<body>
    <div>
        <b>This is a Strongly Typed View</b> <br /><br />

        <u>Customer Details</u><br />
        Customer Name : @Model.FirstName @Model.LastName<br />
        @if (Model.PurchaseAmount > 10.00)
        {
            @:Purchase Amount:
            <span style="color:red">
                 @Model.PurchaseAmount.ToString("C")
            </span>

        }
        else
        {
            <span style="color:blue">
                Purchase Amount: @Model.PurchaseAmount.ToString("C")
            </span>
        }
    </div>
</body>
</html>


View 3 (Strongly Typed View)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@*This is a View Model*@

@model MVC1.ViewModels.PurchaseViewModel

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>View 4</title>
</head>
<body>
    <div>
        <b>This is a View Model</b> <br /><br />

        <u>Customer Details</u><br />
        Customer Name : @Model.CustomerName<br />
        Purchase Amount: @Model.PurchaseAmount.ToString("C")<br />
        Saleman Name: @Model.SalesmanName
    </div>
</body>
</html>


View 4 (View Model)

Controllers

Controllers are classes where most of the coding logic should reside. Controllers are responsible for processing incoming requests, handling input, saving data, and sending the response back to the client. By MVC convention, the controllers must reside in a Controllers folder in the main project directory. It is required that the name of controllers end with Controller (e.g. HomeController.cs). As discussed earlier, the requests take the form of URLs which are routed to public action methods inside the controller. Action methods typically return one of the defined types of action results (see table above). If the controller returns a result which is not an action result (e.g. an integer or date), then the result is wrapped in a ContentResult automatically.

Also discussed earlier, in Web Forms user interaction is based on pages and handling and raising the events from the page oro from controls on the page. In MVC, instead of pages and events, user interaction is based on controllers and action methods. A user enters a URL in the browser and MVC routes the request to an action method which is processed on the server. MVC's routing engine is configured with a default pattern in the scaffolding. The default route can be modified or supplemented with additional routing patterns. The routing engine allows alterations for the routing of URLs and associated parameters which are passed to action methods.

Action Filters can also be used as annotations to modify the way an action method, or the entire controller, executes. Below are some of the action filters available from the framework, however custom action filters can also be created.

Name Description
OutputCache Caches the Output from a Controller
ValidateInput Turns Off Request Validation
Authorize Restrict Action to Authorized Users
ValidateAntiForgeryToken Protects Against Cross-Site Request Forgeries
HandleError Specifies View to Render for Unhandled Exceptions


Action Filters

Models

In ASP.NET, Models are classes which control the data. Data stores are defined within the model. There are varying opinions about which, and how much logic should reside in the Model as opposed to residing in the controller. It is common to find the belief that Models should only contain the Domain Logic (Domain being the object or process which is being represented) should reside in the Model (e.g. How an email address should look). While the logic which describes business work flow should reside in the Controller. The main concern with the placement of the logic (controller vs model) is to maintain's MVC's core concept of Separation of Concerns, which states that Models, Views, and Controllers are loosely coupled, and any one does not need to know anything about the other. So models should not have dependencies on Controllers or Views. It is also advisable to keep models independent from one another as much as possible.

Models are typically associated with the business data stores, such as those stored in a database. However special models are also used to pass data from the controller to view. These are called View Models. Some will argue that View Models should only contain the data, and not the logic to populate the data. However it is common to find the logic for populating the data in the View Model in either the controller, or in the View Model itself.

Anatomy of a Typical ASP.NET MVC Project

  1. Views - often represent CRUD operations, with names such as: Create, Delete, Details, Edit, Index, and Updatexxxxx. Also have shared views (_Layout, Error) to be used with other views. Also Partial Views which refresh only portions of a view commonly used with Ajax. Newer versions use the Razor engine (.cshtml/.vbhtml)

  2. Models - contains public properties and data annotations (e.g. Data Type, String Length, Display Name, Display Format). Also logic for getting and formatting the data (Such as database retrieval or stringing together First and Last to make Full Name). When using Entity Framework, there are often virtual properties which can be overridden to support lazy loading and change tracking. The navigation properties (think foreign keys) are defined as virtual.

  3. View Models - similar to models, but are used to pass data from controllers to views.

  4. Controllers - contain the action methods (e.g. Create, Delete, Details, Edit, Index, and Updatexxxxx) for performing the logic required the destination (frequently a view).



Tags: