View Model Design And Use In Razor Views

The recommended practice for transferring data to and from views in ASP.NET MVC is to use a View Model. But what is a View Model? How to you design one and how should they be used? This article attempts to provide answers to those questions.

In the olden days of web development, developers used RecordSet objects or more recently DataSets or DataTables as a means to transfer data from the database to a view template. The View template might have been a classic ASP file containing a mix of HTML and server-side code, or a Web Form consisting of databound server controls like a GridView or ListView. Regardless, the data is untyped and working with it usually consists of referring to items by index or by using "magic strings" to reference data container values that borrow from the schema of the database that the data originated from.

The MVC framework introduced the idea of strongly-typed views to ASP.NET, primarily to provide some Intellisense support to working with data in Views, compile-time type checking, remove the need to cast objects to other types in the View and to provide the ability to scaffold Views from the Model that the View derives from. Developers can still pass "untyped" data to Views using the ViewBag (or ViewData) mechanism. This is the quickest way to throw arbitrary values at a View. In fact, the default MVC 3 templated Home controller shows how to pass the string ""Welcome to ASP.NET MVC!" to the Index View using ViewBag.

Strongly-typed Views feature the @model directive at the top of a Razor ViewEngine file, which specifies the actual type that the View derives from:

@model ViewModelSample.Models.MyModel

This is added automatically when you use the View creation dialogue and select the option to make the View strongly-typed:

The Model class dropdown will become enabled, and will list all classes available to your project. In this particular example, I have added an ADO.NET Entity Data Model derived from the Northwind sample database to the MVC application being used for illustrative purposes. You can see the familiar auto-generated Product, Customer and Category classes in the dropdown list above.

When the View is compiled, a C# class is created:

public class _Page_Views_Home_Index_cshtml : System.Web.Mvc.WebViewPage<ViewModelSample.Models.MyModel>

The name of the class is derived from the name and location of the View file, and inherits from WebViewPage<TModel>, and it is this that provides the strong-typing and IntelliSense support etc. If no View Model type is set in a model directive, the type that is used instead is dynamic:

public class _Page_Views_Home_Index_cshtml : System.Web.Mvc.WebViewPage<dynamic>
What goes into the View Model?

This is the question that seems to be asked most often. So far as the Add View dialogue is concerned any class in the correct location is a candidate for a strongly-typed View. The collection of classes that were generated by the Entity Framework from the Northwind database are usually known as Domain Entities. It is not unusual to find Views deriving directly from these entities in tutorials and samples. One of the main reasons for this is that it is a quick route to generating demo-code. And sometimes it might even be appropriate where the system being developed is one that largely provides a CRUD application over those entities. If you want to create or update a Category in Northwind, all you really need is a CategoryName and Description property.

Data Annotation attributes are used to manage model validation at property level, as well as display labels and some aspects of scafoolding views. If the model class code is generated automatically, such as with the entity Framework, the file defining the domain entities is regenerated whenever the database is changed. You can use "buddy" or partial classes to apply attributes to domain entity properties. Here's a buddy class for the Category class:

public partial class Category

It is empty, but has its own attribute - the MetadataType attribute which associates the source of the metadata to be applied to the Category class. In this case, the attribute points to a type called CategoryMetadata whose definition is as follows:

public class CategoryMetadata
    [HiddenInput(DisplayValue = true)]
    public int CategoryId { get; set; }

    [Required, Display(Name = "Category Name")]
    public string CategoryName { get; set; }

Regardless how many times the edmx file is regenerated, the metadata attributes are safe from harm.

The real world, however, is not often as straightforward. Usually, Views are complex and include artifacts from more than one domain entity. And perhaps only a subset of any entity's properties. The solution is to create a class whose sole role is to act as a container for a specific View's data. Or a Model for the View, if you will, or a View Model. A common approach to producing a View Model is to compose it from some domain entities and perhaps a sprinkling of properties. A View for adding a new product to the Northwind database will need fields for all of the Product properties together with a way of specifying which Category the new Product object belongs to. Here's something that will do the job:

public class CreateProductViewModel

    public Product Product { get; set; }

    [Required, Display(Name = "Select a category")]
    public int CategoryId { get; set; }
    public SelectList Categories { get; set; }
    [Required, Display(Name = "Select a supplier")]
    public int SupplierId { get; set; }
    public SelectList Suppliers { get; set; }

The Product object comes directly from the domain entities generated by the Entity Framework. It will benefit from any validation etc attributes that may have been applied to a buddy class. The advantage of this approach is that code is reused in a DRY way, and the Product property needs little to no work once validated to prepare it for persistence by the data access layer.


There is a school of thought that domain entities are not the place for setting validation rules or scaffolding and labelling instructions, because these are are purely presentational concerns. Therefore the entity should not be exposed to the presentation layer, even as part of a composite View Model class. There are also security concerns related to mass-assignment vulnerabilities and over-posting attacks where malicious users can craft HTTP requests that include values for entity properties that are not included in the HTML form. The default model binding within MVC will cause those values to be updated or added along with legitimate fields. A built-from-the-ground up View Model solves both these concerns. Rather than include a domain entity (and all of its properties), you only include properties that are required for the specific View. Taking this approach, the CreateProductViewModel will look slightly different:

public class CreateProductViewModel
    [Required, Display(Name = "Product Name"), MaxLength(100)]
    public string ProductName { get; set; }
    [Required, Display(Name = "Quantity Per Unit"), MaxLength(20)]
    public string QuantityPerUnit { get; set; }
    [Required, Display(Name = "Price per unit")]
    public double UnitPrice { get; set; }
    [Required, Display(Name = "Reorder Level")]
    public int ReorderLevel { get; set; }
    [Required, Display(Name = "Select a category")]
    public int CategoryId { get; set; }
    public SelectList Categories { get; set; }
    [Required, Display(Name = "Select a supplier")]
    public int SupplierId { get; set; }
    public SelectList Suppliers { get; set; }

Only those properties that need to be are exposed through the highly customised Vew Model. The Product class has a Discontinued property - a bool. This highly customised View Model doesn't include that property so any attempt to set the Discontinued value by over posting using the revised View Model will not work - so long as the parameter to the Controller Action accepts the View Model and not a Product object. So this approach helps to ensure separation of concerns and offers some additional security, but it means that the values posted to the controller need to be mapped to an entity to be persisted. The data layer deals with Product objects, not View Models. For fairly simple objects, that should be too much trouble:

public ActionResult Create(CreateProductViewModel model)
    if(ModelState.IsValid) {
        var product = new Product {
                          ProductName = model.ProductName,
                          CategoryID = model.CategoryId,
                          SupplierID = model.SupplierId,
                          QuantityPerUnit = model.QuantityPerUnit
        return RedirectToAction("Index");
    return View(model);

However, mapping View Models to entities is made a lot simpler using a tool - AutoMapper, which is described as a convention-based object mapper. In other words, it maps one object (the View Model) to another (the Entity) based on the convention of properties on each object being named the same. It's actually more flexible than that - you can tell it to map mismatched properties too. AutoMapper is available from Nuget. You can access it within Visual Studio by going to Tools > Library Package Manager > Package Manager Console, then typing

PM> Install-Package AutoMapper

Once it has installed successfully, you simple create a mapping between two objects, then sit back:

public ActionResult Create(CreateProductViewModel model)
    if(ModelState.IsValid) {
        var product = Mapper.Map<CreateProductViewModel, Product>(model);
        return RedirectToAction("Index");
    return View(model);

My preference is to generate View Models specific for particular Views. While this may involve extra coding - and some might say a duplication of properties across entities and View Models, AutoMapper helps to minimise the additional work involved.


Date Posted:
Last Updated:
Posted by:
Total Views to date: 65828


- Zeljko

Shouldn't the line:
be called outside of the controller, at startup of the application?

- Mike


Yes, you are right - thanks. The code here is example only, but I will amend things to make that clearer.

- Zeljko

And something else regarding Automapper... Though I use it like you to map the viewmodel to the model, the author of Automapper doesn't think it's appropriate. He says Automapper was designed to 'flatten' the model (model to viewmodel conversion) but not the way round.

- Jules Bartow


You have the most cogent intro to ViewModels anywhere. Thank you.

However, inserts are easy. Most introductions seem to avoid the more difficult updates like the plague.

I'm looking for the next step in your excellent explanation with a similar walkthrough of using Lambda selection of joined tables between complex types with updates where a ViewModel represents subsets of multiple domain entities including Table per Type (TPT) inheritance with 1:0..1 relationships and the corresponding attaches and entry state changes using DbContext in Razor MVC pages.

Can you hold our hands (virtually) and coach us through the rest of the basics? Please.

I want to make ancestor errors and foreign key constraint violations a thing of the past.

- Mike


That's more of an Entity Framework topic than an ASP.NET one.

- Zipper

Great article Mike.

Any chance you can show how to retrieve the data as well as update it? I have yet to find a good example of all three scenarios on a semi-complex ViewModel (like yours which is perfect by the way in terms).


- Andi

I would like some property inheritance property. Something like that in your ViewModel:

public string ProductName { get; set; }

Because i feel, that no one can have the properties in sync

- Donald

Hi, May I please ask what the disadvantages of using the property directly are. I was referred to this blog from another where they said you are subject to Model Injection. Please clarify on this and how it can be done. I have another example I saw where their ViewModel derives a ViewModelBase where T is the domain entity. So instead of have standalone backing properties, they have a ModelObject which is actually your domain entity. What is the best way of using your view models?

- Mike


It would be useful if you said which blog referred you here so I can try to understand what they are talking about.
Add your comment

If you have any comments to make about this article, please use this form to do so. Make sure that your comment relates specifically to the article above. More general comments can be posted through the form on the Contact page.

Please note, all comments are moderated, and I end up deleting quite a lot. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Requests to fix your code (post a question to instead, please)
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam

I do not pass email addresses on to spammers, so a valid one will assist me in responding to you personally if required.

Recent Comments

kaleem 4/16/2015 9:14 AM
In response to ASP.NET MVC, Entity Framework, One-to-Many and Many-to-Many INSERTS
hi this is very helpful ASP.NET MVC, Entity Framework, One-to-Many and Many-to-Many INSERTS if to...

cranston mason 4/16/2015 8:49 AM
In response to Managing Checkboxes And Radios In ASP.NET Razor Web Pages
How do you include a checkbox at the View module and send its values to controller to be processed?...

vamsi 4/15/2015 5:40 AM
In response to Sessions in ASP.NET 5
good article...

James Chaney 4/14/2015 8:44 PM
In response to 7 C# 6.0 Features That Every ASP.NET Developer Should Know About
Question on #5 - I don't see where this gets you out of a NullReferenceException if returns null is...

Grey 4/14/2015 6:09 PM
In response to Getting the identity of the most recently added record
Nice work....

Anh Huynh 4/14/2015 3:36 PM
In response to Create PDFs in ASP.NET - getting started with iTextSharp
I was successfully create and display PDF file from my localhost but when I move the aspx to the I...

Hisham Abdullah Bin Ateya 4/14/2015 7:00 AM
In response to Sessions in ASP.NET 5
Thanks Mike for sharing this article. George it will be nice if we let the web developers implement...

CTR 4/14/2015 6:39 AM
In response to Integrating Web API with ASP.NET Razor Web Pages
Thanks Mike, new to web pages. learning a lot from your posts, Making Ajax calls to Web API extend...

Bayu Angkasa 4/13/2015 11:27 AM
In response to The Difference Between @Helpers and @Functions In WebMatrix
Four years after you wrote it, I still find out how lucky I am to read your posts ... Thank you Mike...

abedon 4/10/2015 9:17 PM
In response to ASP.NET 5 Middleware, Or Where Has My HttpModule Gone?
I feel the title of this article is not that felicitous. ASP.NET 5 is built of top of the concept...