Models and Validation in ASP.NET MVC

In the ASP.NET MVC framework, the model is the part of the application that is responsible for the core application or business logic. Model objects typically access data from a persistent store, such as SQL Server, and perform the business logic on that data. Models are application specific, and therefore the ASP.NET MVC framework puts no restrictions on the kinds of model objects you can build. For instance, you can use ADO.NET DataSet or DataReader objects, or you can use a custom set of domain objects. You can also use a combination of object types to work with data.

The model is not a specific class or interface. A class is part of the model not because it implements a certain interface or because it derives from a certain base class. Instead, a class is part of the model because of the role that the class plays in the ASP.NET MVC application, and where the class is located in the folder structure of the application. A model class in an ASP.NET MVC application does not directly handle input from the browser, nor does it generate HTML output to the browser.

Defining the Model

Model objects are the parts of the application that implement the domain logic, also known as business logic. Domain logic handles the data that is passed between the database and the UI. For example, in an inventory system, the model keeps track of the items in storage and the logic to determine whether an item is in stock. In addition, the model would be the part of the application that updates the database when an item is sold and shipped out of the warehouse. Often, the model also stores and retrieves model state in a database.

Integrating the Model and Controller

The recommended folder to put model classes in is the Models folder that is provided by Visual Studio in the ASP.NET MVC application template. However, it is also typical to put model classes in a separate assembly, so that you can reuse these classes in different applications.

Using model classes from a controller typically consists of instantiating the model classes in controller actions, calling methods of model objects, and extracting the appropriate data from these objects to display in views. This is the recommended approach for implementing actions. It also maintains separation between the logical elements of the application, which makes it easier to test the application logic without having to test it through the user interface.

The following example shows a simple model class that represents a person.

Public Class Person

    Private _Id As Integer
    Public Property Id() As Integer
        Get
            Return _Id
        End Get
        Set(ByVal value As Integer)
            _Id = value
        End Set
    End Property

    Private _Name As String
    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Private _Age As Integer
    Public Property Age() As Integer
        Get
            Return _Age
        End Get
        Set(ByVal value As Integer)
            _Age = value
        End Set
    End Property

    Private _Street As String
    Public Property Street() As String
        Get
            Return _Street
        End Get
        Set(ByVal value As String)
            _Street = value
        End Set
    End Property

    Private _City As String
    Public Property City() As String
        Get
            Return _City
        End Get
        Set(ByVal value As String)
            _City = value
        End Set
    End Property

    Private _State As String
    Public Property State() As String
        Get
            Return _State
        End Get
        Set(ByVal value As String)
            _State = value
        End Set
    End Property

    Private _Zipcode As Integer
    Public Property Zipcode() As Integer
        Get
            Return _Zipcode
        End Get
        Set(ByVal value As Integer)
            _Zipcode = value
        End Set
    End Property
End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcSimpleModelBinding.Models
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public int Zipcode { get; set; }
    }
}

Model Binders

A model binder in MVC provides a simple way to map posted form values to a .NET Framework type and pass the type to an action method as a parameter. Binders also give you control over the deserialization of types that are passed to action methods. Model binders are like type converters, because they can convert HTTP requests into objects that are passed to an action method. However, they also have information about the current controller context.

A model binder lets you associate a class that implements the IModelBinder interface using an action-method parameter or using a type. The IModelBinder interface contains a GetValue method that the framework calls in order to retrieve the value of a specified parameter or type. The DefaultModelBinder class works with most .NET Framework types, including arrays and IList, ICollection, and IDictionary objects.

Example of Model Binding

The following example shows how to implement simple model binding. The model used in this example is the Person class that was defined in a previous example. This example includes a PersonController class and an Index view, a Create view, and a Details view. The PersonController class creates a list for storing Person objects. The Index view displays the Id and Name properties for each Person object in the list. The Create view enables the user to enter the information for a person. The Details view displays all the information for a selected person.

The following example shows the PersonController class:

Public Class PersonController
    Inherits System.Web.Mvc.Controller

    Shared people As New List(Of Person)()

    '
    ' GET: /Person/
    Function Index() As ActionResult
        Return View(people)
    End Function

    '
    ' GET: /Person/Details/5
    Function Details(ByVal person As Person) As ActionResult
        Return View(person)
    End Function

    '
    ' GET: /Person/Create
    Function Create() As ActionResult
        Return View()
    End Function

    '
    ' POST: /Person/Create
    <AcceptVerbs(HttpVerbs.Post)> _
    Function Create(ByVal person As Person) As ActionResult
        If Not ModelState.IsValid Then
            Return View("Create", person)
        End If

        people.Add(person)

        Return RedirectToAction("Index")
    End Function
End Class
public class PersonController : Controller
{
    static List<Person> people = new List<Person>();

    //
    // GET: /Person/
    public ActionResult Index()
    {
        return View(people);
    }

    //
    // GET: /Person/Details/5
    public ActionResult Details(Person person)
    {
        return View(person);
    }

    //
    // GET: /Person/Create
    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Person/Create
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        if (!ModelState.IsValid)
        {
            return View("Create", person);
        }

        people.Add(person);

        return RedirectToAction("Index");
    }
}

The following example shows the Index view:

<h2>Index</h2>

<p>
    <%=Html.ActionLink("Create New", "Create")%>
</p>





<table>
    <tr>
        <th></th>
        <th>
            Id
        </th>
        <th>
            Name
        </th>
    </tr>
<% For Each person In Model%>
    <tr>
        <td>
            <%=Html.ActionLink("Details", "Details", person)%>
        </td>
        <td>
            <%=Html.Encode(person.Id)%>
        </td>
        <td>
            <%=Html.Encode(person.Name)%>
        </td>
    </tr>
<% Next%>
</table>

<h2>Index</h2>





<table>
    <tr>
        <th></th>
        <th>
            Id
        </th>
        <th>
            Name
        </th>
    </tr>
<% foreach (var person in Model) { %>
    <tr>
        <td>
            <%= Html.ActionLink("Details", "Details", person )%>
        </td>
        <td>
            <%= Html.Encode(person.Id) %>
        </td>
        <td>
            <%= Html.Encode(person.Name) %>
        </td>
    </tr>
<% } %>
</table>


<p>
    <%= Html.ActionLink("Create New", "Create") %>
</p>

The following example shows the Create view:

<h2>Create</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% Using Html.BeginForm()%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Id">Id:</label>
            <%= Html.TextBox("Id") %>
            <%= Html.ValidationMessage("Id", "*") %>
        </p>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %>
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Age">Age:</label>
            <%= Html.TextBox("Age") %>
            <%= Html.ValidationMessage("Age", "*") %>
        </p>
        <p>
            <label for="Street">Street:</label>
            <%= Html.TextBox("Street") %>
            <%= Html.ValidationMessage("Street", "*") %>
        </p>
        <p>
            <label for="City">City:</label>
            <%= Html.TextBox("City") %>
            <%= Html.ValidationMessage("City", "*") %>
        </p>
        <p>
            <label for="State">State:</label>
            <%= Html.TextBox("State") %>
            <%= Html.ValidationMessage("State", "*") %>
        </p>
        <p>
            <label for="Zipcode">Zipcode:</label>
            <%= Html.TextBox("Zipcode") %>
            <%= Html.ValidationMessage("Zipcode", "*") %>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% End Using %>

<div>
    <%=Html.ActionLink("Back to List", "Index") %>
</div>
<h2>Create</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Id">Id:</label>
            <%= Html.TextBox("Id") %>
            <%= Html.ValidationMessage("Id", "*") %>
        </p>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %>
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Age">Age:</label>
            <%= Html.TextBox("Age") %>
            <%= Html.ValidationMessage("Age", "*") %>
        </p>
        <p>
            <label for="Street">Street:</label>
            <%= Html.TextBox("Street") %>
            <%= Html.ValidationMessage("Street", "*") %>
        </p>
        <p>
            <label for="City">City:</label>
            <%= Html.TextBox("City") %>
            <%= Html.ValidationMessage("City", "*") %>
        </p>
        <p>
            <label for="State">State:</label>
            <%= Html.TextBox("State") %>
            <%= Html.ValidationMessage("State", "*") %>
        </p>
        <p>
            <label for="Zipcode">Zipcode:</label>
            <%= Html.TextBox("Zipcode") %>
            <%= Html.ValidationMessage("Zipcode", "*") %>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

<div>
    <%=Html.ActionLink("Back to List", "Index") %>
</div>

The following example shows the Details view:

<h2>Details</h2>

<fieldset>
    <legend>Fields</legend>
    <p>
        Id:
        <%= Html.Encode(Model.Id) %>
    </p>
    <p>
        Name:
        <%= Html.Encode(Model.Name) %>
    </p>
    <p>
        Age:
        <%= Html.Encode(Model.Age) %>
    </p>
    <p>
        Street:
        <%= Html.Encode(Model.Street) %>
    </p>
    <p>
        City:
        <%= Html.Encode(Model.City) %>
    </p>
    <p>
        State:
        <%= Html.Encode(Model.State) %>
    </p>
    <p>
        Zipcode:
        <%= Html.Encode(Model.Zipcode) %>
    </p>
</fieldset>
<p>
    <%=Html.ActionLink("Back to List", "Index") %>
</p>
<h2>Details</h2>

<fieldset>
    <legend>Fields</legend>
    <p>
        Id:
        <%= Html.Encode(Model.Id) %>
    </p>
    <p>
        Name:
        <%= Html.Encode(Model.Name) %>
    </p>
    <p>
        Age:
        <%= Html.Encode(Model.Age) %>
    </p>
    <p>
        Street:
        <%= Html.Encode(Model.Street) %>
    </p>
    <p>
        City:
        <%= Html.Encode(Model.City) %>
    </p>
    <p>
        State:
        <%= Html.Encode(Model.State) %>
    </p>
    <p>
        Zipcode:
        <%= Html.Encode(Model.Zipcode) %>
    </p>
</fieldset>
<p>
    <%=Html.ActionLink("Back to List", "Index") %>
</p>

See Also

Other Resources

ASP.NET MVC 2