Consulting Services
Consulting Services

ASP.NET MVC

Introduction to ASP.NET MVC

One of the hardest things about working in this field is trying to keep up with all of the new technologies that are released each year. It seems that every few years a new product comes out and forces you to relearn everything. When Microsoft first announced ASP.net MVC a lot of people thought that this would be the case again. The good news is that you don’t have to forget everything you have already learned about ASP.net. MVC is meant to be another option for doing web development, not a replacement for ASP.net. My goal today is to give you an introduction to this technology and how it differs from ASP.net.

What is ASP.net MVC?

MVC stands for Model View Controller. It is an architectural design pattern that is used to separate an application into three components:

  • Model - A set of classes that describes the data you are working with and the business rules associated with the data.
  • View - The User Interface elements.
  • Controller - Handles the communication with the user and bridges the gap between the data and the UI.

In the context of ASP.net the Model would most likely be your database access and business objects. The view would be a page with HTML markup and Javascript. The controllers are special classes that communicate with your models and render views to the user.

What is ASP.net MVC?

Here are some of the key differences between ASP.net WebForms and ASP.net MVC:

  • HTTP Requests in MVC are made to controller actions and not pages
  • MVC does not use the WebForms postback model
  • MVC does not use ViewState

One of the main differences between ASP.net WebForms and ASP.net MVC is that when you make an HTTP request in MVC, you are making a request to an action on a controller and not to a file. When you see the URL http://www.example.com/products/view.aspx in a WebForms application you are making a request to the file view.aspx in the /products/ folder. In MVC if you see the URL http://www.example.com/products/view you are (with default settings) making a request to the View action on the Products controller. It is up to the controller to decide which view to render.

Another thing that is different in MVC is that the MVC does not use the WebForms postback model. In MVC you have complete control over where your forms are POSTing to. In WebForms it was very difficult to have multiple forms on a single page that POSTed to different pages. In MVC it is simple because you have complete control over the markup that is produced:

<form action=”/products/save” method=”post”> <input id=”type=”text” id=”username” /> <input type=”submit” value=”Save” /> </form>

The above code would POST the value of the input field to the Save action method of the Products controller.

The last difference between MVC and WebForms that I am going to cover is the lack of ViewState in MVC. Since HTTP is a stateless protocol, WebForms used ViewState to save the state of your application in between postbacks. One of the downsides to not having ViewState in your MVC applications is that some of the legacy WebForms controls that rely heavily on it may not function in an MVC application.

Example Application

So far I have talked a lot about MVC but we haven’t seen any actual code. Below I will show a simple application that is used to input a person’s first and last name and then display a message on the screen when the click the submit button.

MVC Model - /Models/TestModel.cs

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.ComponentModel.DataAnnotations; using System.ComponentModel; namespace MvcTest.Models { public class TestModel { [Required] [DisplayName("First Name")] public string FirstName { get; set; } [Required] [DisplayName("Last Name")] public string LastName { get; set; } } }

This first class is our MVC Model. It is a simple class called TestModel that has FirstName and LastName string properties. The class uses the DataAnnotations namespace so that the MVC framework knows that both fields are required. The DisplayName attribute will be used to provide a label for our view when we use the Html.LabelFor() helper method.

MVC Controller - /Controllers/TestController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using MvcTest.Models;

namespace MvcTest.Controllers
{
    public class TestController : Controller
    {
       // GET: /test/
       // GET: /test/index
       public ActionResult Index()
       {
           // return the default view
           return View();
       }

       // POST: /test/
       // POST: /test/index
       [HttpPost]
       public ActionResult Index(TestModel model)
       {
           if (ModelState.IsValid)
           {
               TempData["Model"] = model;

               // everything is good - redirect to the welcome page
               return RedirectToAction("Welcome");
           }

           // something failed - redisplay the form
           return View(model);
       }

       // GET: /test/welcome
       public ActionResult Welcome()
       {
           if (TempData["Model"] != null)
           {
               TestModel model = (TestModel)TempData["Model"];

               // display the welcome view
               return View(model);
           }

           // model is not present - redirect back to index
           return RedirectToAction("Index");
       }
    }
}

This next class is our Controller. This is where the heart of the application is. The TestController class inherits from the base MVC Controller class and has three methods: Index(), Index(TestModel) and Welcome(). The first Index() method is the simplest of them all. The only thing it does is return a call to the View() method. Under default settings MVC is going to look for a file called Index.aspx under the /Views/Test/ folder. This method will be accessed via an HTTP GET request similar to: http:///test/ or http:///test/index. Note the lack of an extension such as .aspx. MVC sees the request and routes the request to our Index() controller method by default. The next method is also called Index but takes in our TestModel object. The controller first checks to make sure the ModelState is valid. If the model is valid then it will store it into the TempData object (a built in temporary storage mechanism for MVC) and redirect to the Welcome() method in the controller. If the model is not valid then it will display the Index view instead. The method is also marked with the [HttpPost] attribute which means that the controller action will be accessed through an HTTP POST instead of a GET. The last method in our controller is called Welcome(). This method will check our TempData object for the Model property and will display the Welcome view if it exists. If the data does not exist then it will redirect back to the Index() controller action.

MVC View - /Views/Test/Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
        Inherits="System.Web.Mvc.ViewPage<MvcTest.Models.TestModel>" %>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Index</h2>
   
    <% using( Html.BeginForm() ) { %>
       <div>
           <div class="editor-label">
               <%= Html.LabelFor( m => m.FirstName ) %>             
           </div>
               
           <div class="editor-field">
               <%= Html.TextBoxFor(m => m.FirstName ) %>
               <%= Html.ValidationMessageFor(m => m.FirstName ) %>
           </div>
               
           <div class="editor-label">
               <%= Html.LabelFor( m => m.LastName ) %>             
           </div>
               
           <div class="editor-field">
               <%= Html.TextBoxFor(m => m.LastName ) %>
               <%= Html.ValidationMessageFor(m => m.LastName)%>
           </div>
               
           <input type="submit" value="Submit" />
       </div>
    <% } %>
</asp:Content>

MVC View - /Views/Test/Welcome.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<MvcTest.Models.TestModel>" %>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Welcome</h2>

    Welcome to MVC <%= Model.FirstName %> <%= Model.LastName %>.
</asp:Content>

Finally we have two .aspx files. We have one for our data entry page: Index.aspx. The page is a mix of standard HTML and MVC helper methods. It starts off by creating a form tag with the following line: <% using( Html.BeginForm() ) { %>. This will create a form that will post to the Index action method by default. The next significant lines are the following: <%= Html.LabelFor(m => m.FirstName) and <%= Html.TextBoxFor(m => m.FirstName) %>. These helper methods are used to create a label and text box based on our TestModel class. You will notice that in the Page directive at the very top of the file that the Page is strongly typed and inherits from the ViewPage<TestModel>. This allows our View to have a full understanding of what is in our model and the code editor will have intellisense. Very cool! The last important piece of this page is our submit button: <input type="submit" value="Submit" /> This is pure HTML. When the user clicks it the page will POST to our Index action method. The second page simply displays a message on the screen with the following call: Welcome to MVC <%= Model.FirstName %> <%= Model.LastName %>. Now that we have the individual pieces of the puzzle we can begin to piece them together. The user will first come into our site by typing in the following address: http://<server>/test. They will be presented with two text boxes and a button. When they click the Submit button it will POST to the Index(TestModel) method. MVC will automatically bind the text boxes to our TestModel object. The controller will check to see if the Model is valid and redirect the user to the Welcome controller method if it is. If the model is not valid then the user will see the same page with error messages on the text boxes (because of the Html.ValidationMessageFor() helper methods).When the Welcome method of the controller is accessed it will check the TempData object for our model and display the page to the user, which displays a welcome message to the user. If the model does not exist (this would be the case if the user accessed the /test/welcome URL without going through the form) then the user is redirected back to /test/. The code is very simple and in my opinion very elegant. One thing to note is that there are many overloads for the Controller methods such as View. In my example, the controller always displays a View with the same name as the method. This isn’t always the case. In the Welcome() controller method I redirect the user to the Index method if the model does not exist. An alternative way to do this would be to do the following instead: return View(“ModelNotFound”); MVC would instead look for a file called /Views/Test/ModelNotFound.aspx and display that to the user instead of redirecting to the original page. This would allow you to display a message to the user informing them that there was a problem. I hope you enjoyed this brief look into MVC. We have only scratched the surface on what is possible in this framework. There are many other great things about this framework and if you would like to learn more I encourage you to go to www.asp.net/mvc or download the free NerdDinner MVC application from www.nerddinner.com. Feel free to contact me with any questions or comments at travisellis@deliveron.com as well.