liveBook · Manning

Model directive

As explained in Pro ASP.NET Core 7, Tenth Edition

The Razor model directive declares the .NET type of the view model exposed to a Razor view.

Put `@model` at the top of a CSHTML view to declare the type of data the view expects. An action method passes the object to the view; expressions use `Model`—capital M—to access it. `@model` declares the type, while `Model` is the object you render. section 21.3.1 section 21.4.1

Without a declared type, the generated view class uses `RazorPage<dynamic>`. A misspelled member can then fail when a response is generated. With `@model WebApp.Models.Product`, the generated class uses `RazorPage<WebApp.Models.Product>`: editors can suggest members, and an invalid member is reported during editing or building. section 21.3.1

Listing 21.15 Declaring the type in the Watersports.cshtml file in the Views/Home folder
@model WebApp.Models.Product
<!DOCTYPE html>
<html>
<head>
    <link href="/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <h6 class="bg-secondary text-white text-center m-2 p-2">
        Watersports
    </h6>
    <div class="m-2">
        <table class="table table-sm table-striped table-bordered">
            <tbody>
                <tr><th>Name</th><td>@Model.Name</td></tr>
                <tr>
                    <th>Price</th>
                    <td>@Model.Price.ToString("c")</td>
                </tr>
                <tr><th>Category ID</th><td>@Model.CategoryId</td></tr>
                <tr><th>Tax Rate</th><td>@Model.TaxRate</td></tr>
            </tbody>
        </table>
    </div>
</body>
</html>

A typed product view declares `@model WebApp.Models.Product` before rendering properties through `Model`. section 21.3.1

The declared type can be a collection. For a view receiving products, `@model IQueryable<Product>` lets `@foreach` render each product’s name, description, and price. Razor view model data is always nullable, even when its declared type is not, so the loop can use `Model ?? Enumerable.Empty<Product>()`. The view needs to know how to display a product, not how the products were obtained. section 7.3.2

Use a fully qualified type name, or import its namespace in `Views/_ViewImports.cshtml` with `@using WebApp.Models` and write `@model Product`. A partial view is also a CSHTML view and can declare its own model type; a row partial, for example, uses a `Product` to render name and price cells. section 21.3.1 section 22.5.2

Listing 22.26 The contents of the _RowPartial.cshtml file in the Views/Home folder
@model Product

<tr>
   <td>@Model.Name</td>
   <td>@Model.Price</td>
</tr>

The row partial shows `@model Product` alongside the `Model` property expressions that fill its table cells. section 22.5.2

Watch the change of meaning in a Razor Page. There, `@model IndexModel` selects a page model class, not an object supplied by a controller action. A page model can receive a service through its constructor and populate a property in a request handler; the page then renders that property through `Model`. section 23.2.2

Listing 23.4 The contents of the Index.cshtml file in the Pages folder
@page
@model IndexModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@using WebApp.Models;

<!DOCTYPE html>
<html>
<head>
   <link href="/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
   <div class="bg-primary text-white text-center m-2 p-2">
       @Model.Product?.Name
   </div>
</body>
</html>

@functions {

   public class IndexModel : PageModel {
       private DataContext context;
               
       public Product? Product { get; set; }
               
       public IndexModel(DataContext ctx) {
           context = ctx;
       }
               
       public async Task OnGetAsync(long id = 1) {
           Product = await context.Products.FindAsync(id);
       }
   }
}

The `/index` Razor Page selects `IndexModel`, loads a product in `OnGetAsync`, and displays `@Model.Product?.Name`. section 23.2.2

How Pro ASP.NET Core 7, Tenth Edition covers it

How deep it goes
Explains generated `RazorPage<T>`, editor and build-time checking, nullable view data, view imports, and the distinct Razor Page use.
Examples
Uses product-detail and product-list views, a product table-row partial, and a Razor Page that displays a loaded product.
What it assumes
Assumes familiarity with C# types and properties while explaining the difference between `@model` and `Model`.
What you can do after
Apply it in CSHTML to type-check model expressions and distinguish controller-view models from Razor Page models.
How it connects
Connects controller actions, view models, Razor expressions, view imports, partial views, and Razor Pages.

Also explained in

Compare how 2 books explain model directive →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Pro ASP.NET Core 7, Tenth Edition. The section links point to the parts of the book it draws on.