Understanding Models in ASP.NET Core MVC

In the Model-View-Controller (MVC) architectural pattern, the Model represents the application's data and the business logic that governs it. It's responsible for managing the state of the application. In ASP.NET Core MVC, models are typically plain C# classes (POCOs - Plain Old CLR Objects) that define the structure of your data and any validation rules or operations related to that data.

Creating Your First Model

Let's create a simple model to represent a product in an e-commerce application.


using System.ComponentModel.DataAnnotations;

namespace Msdn.Tutorials.AspNetCore.Mvc.Models
{
    public class Product
    {
        public int Id { get; set; }

        [Required(ErrorMessage = "Please enter a product name.")]
        [StringLength(100, ErrorMessage = "Product name cannot exceed 100 characters.")]
        public string Name { get; set; }

        [Required(ErrorMessage = "Please enter a description.")]
        public string Description { get; set; }

        [Required(ErrorMessage = "Price is required.")]
        [Range(0.01, 10000.00, ErrorMessage = "Price must be between $0.01 and $10,000.00.")]
        [DataType(DataType.Currency)]
        public decimal Price { get; set; }

        [Required(ErrorMessage = "Category is required.")]
        [StringLength(50)]
        public string Category { get; set; }
    }
}
                

Key Concepts

  • Data Representation: Models define the shape of your data using properties. These properties can be of various types, such as string, int, decimal, DateTime, etc.
  • Validation: ASP.NET Core MVC provides powerful data annotation attributes (from System.ComponentModel.DataAnnotations) to enforce validation rules directly on your model properties. This includes attributes like [Required], [StringLength], [Range], and [DataType].
  • Business Logic: While simple models often just hold data, more complex models can encapsulate business logic, such as methods to perform calculations or enforce specific business rules.
  • Data Transfer Objects (DTOs): In larger applications, you might use DTOs to transfer data between different layers of your application or across network boundaries. These are also typically plain C# classes.

Using Models in Controllers and Views

Models are passed from the Controller to the View. The Controller retrieves or manipulates data and then passes a model instance to the View for rendering. The View then binds to the properties of the model to display the information.

For example, a controller action might look like this:


using Microsoft.AspNetCore.Mvc;
using Msdn.Tutorials.AspNetCore.Mvc.Models;

namespace Msdn.Tutorials.AspNetCore.Mvc.Controllers
{
    public class ProductController : Controller
    {
        public IActionResult Index()
        {
            var products = new List
            {
                new Product { Id = 1, Name = "Laptop", Description = "Powerful computing on the go.", Price = 1200.00m, Category = "Electronics" },
                new Product { Id = 2, Name = "Wireless Mouse", Description = "Ergonomic design for comfort.", Price = 25.50m, Category = "Accessories" },
                new Product { Id = 3, Name = "Mechanical Keyboard", Description = "Tactile feedback for typing.", Price = 75.00m, Category = "Accessories" }
            };
            return View(products);
        }

        public IActionResult Details(int id)
        {
            // In a real app, you'd fetch this from a database
            var product = new Product { Id = id, Name = "Sample Product", Description = "A detailed description.", Price = 50.00m, Category = "General" };
            return View(product);
        }
    }
}
                

And a corresponding View (e.g., Views/Product/Index.cshtml) would iterate through the list of products:


@model IEnumerable<Msdn.Tutorials.AspNetCore.Mvc.Models.Product>

@{
    ViewData["Title"] = "Product List";
}

<h1>Products</h1>

<table class="table">
    <thead>
        <tr>
            <th>@Html.DisplayNameFor(model => model.First().Name)</th>
            <th>@Html.DisplayNameFor(model => model.First().Category)</th>
            <th>@Html.DisplayNameFor(model => model.First().Price)</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Category)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
                @Html.ActionLink("Details", "Details", new { id=item.Id })
            </td>
        </tr>
        }
    </tbody>
</table>
                

Best Practices

  • Keep models focused on data and related validation. Avoid putting controller or view-specific logic into models.
  • Use data annotations for validation to keep code clean and declarative.
  • Consider using ViewModels for passing data specifically tailored for a view, especially if the model has more properties than the view needs or if data needs to be combined from multiple sources.
  • For complex operations, consider using Service Layers or Repositories to abstract data access and business logic away from controllers and models.