How to use Models in ASP.NET MVC

.NET MVC Model
Ever wondered why they call it Model-View-Controller? In this post, we'll discuss the Model part of MVC. By the end of this article, you'll know how to pass strongly typed data from a Controller to a Razor View, how to create forms to modify models and how to use attributes on model properties to improve validation.

What is a Model?



A "Model" in MVC is essentialy an object. It is typically a class that you have defined in your project, usually with some { get; set; } properties. It can be as simple or as complex as you like, but in principle, you should consider this as a "Data Transfer Object".

This class helps you pass data from your Controllers to your Views, and keeps the data strongly typed.

Let's start off by creating a custom class that we want to use as a model.


namespace MyWebShop.Models
{
public class ProductModel
{
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public System.DateTime ReleaseDate { get; set; }
public string GTIN { get; set; }
public bool InStock { get; set; }
public double Price { get; set; }
public ushort? MaxOrderQuantityLimit { get; set; }
}
}


If you want to pass an instance of this object model to your home page View, you might do the following:


using System.Web.Mvc;

namespace MyWebShop.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
var product = new Models.ProductModel()
{
ProductName = "Pear ePhone",
GTIN = "123456789",
InStock = true,
Price = 399.99,
ProductDescription = "The greatest mobile phone on earth.",
ReleaseDate = new System.DateTime(2020, 02, 20)
};

return this.View(product);
}

// other Action methods
}
}


The code above creates a very simple product model object with a few properties. Obviously, you would typically do this via a data repository or through your application logic.

The code return this.View(product); tells MVC to create a page which corresponds to the Index page of the Home controller. Typically, this file would be: Views\Home\Index.cshtml

The parameter for the View method can be any object, but the trick comes in the *.cshtml file, where you can specify the model type which will be received from the Controller.

If we open up the Views\Home\Index.cshtml file, we can add some code to the top of the page:


@model MyWebShop.Models.ProductModel


This line tells the Razor page that the Model to be used will be of type ProductModel. Therefore, IntelliSense will provide you the properties, fields and methods of the class in your Razor markup.

The model is accessed in Razor through a predefined { get; } property called Model.

For example, to print the ProductName to the browser, you use:


@this.Model.ProductName


How to use a Model as an Action parameter



For the sake of simplicity, we'll illustrate this on the HomeController.

If you want to use the same Razor View, you can simply create an overload of the Index() method as follows:


using System.Web.Mvc;
using MyWebShop.Models;

namespace MyWebShop.Controllers
{
public class HomeController : Controller
{
[HttpPost]
public ActionResult Index(ProductModel product)
{
// process the model

return this.View(product);
}
}
}


NOTE: We need to specify the [HttpPost] attribute here, otherwise MVC won't be able to tell which Index() method to route requests to.

In order to populate the product parameter when routing to the Index, we need to use something called "Model Binding". This is a process whereby MVC instantiates an object, based on a number of "model binders".

Luckily, MVC has a lot of this functionality built in by default. The object's parameters can be taken from the Query String, from the body of a POST request, and many other ways including by using a custom IModelBinder.

We will use a simple form to post the object back to the server and check that the properties are populated correctly.

Add this markup to your Views\Home\Index.cshtml page:


@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
< input type="submit" value="Submit Product" / >
}


This creates a scope for a form, indicating that we want to Post data to the Index method of the Home Controller. Pretty simple, right?

If you run your project, you'll see the [Submit Product] button on your page. Stick a breakpoint on the new [HttpPost] Index(product) method of your controller, and you'll see that after you click the button, you will be routed through to that method as expected.

Interestingly, the product parameter is not null, but it contains defaults for all the values in the class. So, strings are null, numbers are 0, dates are 1st January, the year of our Lord, 1 A.D. etc...

But this isn't very useful, so let's create a form to modify the object.

Create the model editor form



With standard HTML markup, you would need to create input tags for each property, with the correct types, names, patterns, etc.

Not the case for MVC. It's gonna be super easy, barely an inconvenience!

Modify your Views\Home\Index.cshtml page as follows:


@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
@Html.EditorForModel()
< input type="submit" value="Submit Object" / >
}


Now, run your project again. You'll see that MVC has created a form for you, with all the necessary fields, and the values have been pre-populated according to the data we specified in the original HomeController.Index() method. Nice!

Granted, the form it creates is not particularly beautiful, but you can use templates and CSS to fix that.

Modify some data and hit the submit button. Now, the parameter you have received to the Index(product) method contains the modified data! The updated model is also passed back to the View automatically, but we want to be explicit, and that's why we always use return this.View(product);

If you enter invalid values, for example letters in the MaxOrderQuantityLimit field, you will see a message appear after submitting:

"The value 'three' is not valid for MaxOrderQuantityLimit."

In short, MVC is performing basic validation of the submitted data for your form. Any invalid properties simply won't be bound to the Model, and the ModelState.IsValid property will be set to false.

Refine the model with attributes



Model Attributes are a fantastic way to perform validation of your model without needing to write additional code to check the properties of the object.

Let's refine our model class as follows:


using System;
using System.ComponentModel.DataAnnotations;

namespace MyWebShop.Models
{
public class ProductModel
{
[Required]
[MinLength(5)]
public string ProductName { get; set; }
public string ProductDescription { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
public DateTime ReleaseDate { get; set; }
[MaxLength(14)]
[RegularExpression(@"^[0-9]{12,13,14}$")]
public string GTIN { get; set; }
public bool InStock { get; set; }
[Range(0, double.MaxValue)]
public double Price { get; set; }
[Range(0,99)]
public ushort? MaxOrderQuantityLimit { get; set; }
}
}


The attributes we've added will affect the form directly, and the submission will be validated against these attributes before the ModelState.IsValid property will become true.

Summary



So we've learnt what a model is, how to pass data to a View, how to define the strongly typed model class in the Razor View, how to create an editor form, how to use Attributes to improve data validation, and how to get receive models in Action methods in a Controller.

Happy coding! Please, don't forget to support me!
Hey you! I need your help!

Thanks for reading! All the content on this site is free, but I need your help to spread the word. Please support me by:

  1. Sharing my page on Facebook
  2. Tweeting my page on Twitter
  3. Posting my page on LinkedIn
  4. Bookmarking this site and returning in the near future
Thank you!