10 out of 28 rated this helpful - Rate this topic

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.

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.

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.


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; }
    }
}


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 : 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>

<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>

<% } %>

<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>


Other Resources

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
model bound validation breaks the mvc pattern
yea, this breaks the MVC rule as its putting items such as [Display(Name="My Title")] into the Model. This belongs in the view: http://stackoverflow.com/questions/6046092/asp-net-mvc-model-validation-breaks-mvc-rule/6046104#6046104
Server error in latest version of MVC

I'm getting the following runtime compiler error when I try to view the main Index page in this example:

Compiler Error Message: CS1973: 'System.Web.Mvc.HtmlHelper<dynamic>' has no applicable method named 'ActionLink' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

As the error suggests, the problem is due to the use of an extension method in the following line:

    <%= Html.ActionLink("Details", "Details", person )%>

Changing the code to call the extension method directly fixes the error:

    <%= LinkExtensions.ActionLink(Html, "Details", "Details", person)%>

NullReferenceException
Jenny,

I found the same problem at some stages of the walkthrough. The cause in my case was that the underlying model fields were nullable, but the views hadn't been written to accommodate this.

The solution in my case was to add an if statement to all such renderings. Something like...

<% If Not city Is Nothing Then Response.Write(Html.Encode(city)) End If %>

Hope This Helps,

Rob
Strongly typed ViewPage?
It's a bit odd that the page declaration isn't in the View markup for Index.aspx. I don't know what you've got at the top of your view but I'd expect to see something strongly typed like

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<List<Person>>" %>

If you've got the default System.Web.Mvc.ViewPage<dynamic> in there you won't have a Model object to play with, which is why you got that null reference exception.

I'd normally bind against a custom class (a ViewModel) rather than a generic List as they've done in the example but I suppose it keeps things simple.

NullReferenceException
I am doing this as part of the 'walk through' I created a class under the model folder called Person and pasted the first chunk of code there. Then I created a Controller called PersonController.vb under the Controllers folder and replaced the code there with the next chunk of code. Then I replaced the content area of my index.aspx file under the home folder with the next chunk of code. Next I created a Create View under the Home folder and pasted the next chunk of code in the content area Finally I created a Details View under the home folder and pasted the last chunk of code there.  When I run this code I fail in the Index view on the line that says "for Each person in Model" It says NullReferenceException was handled by user code. What might I do to correct this problem? Thanks.