# Passing a Model to a View

An action hands its view a model with View(model); the view names the model's type with @model and reads it through Model. ViewData carries small extras, such as the page title.

Journeyman · ASP.NET Core · Razor · C# · Updated November 3, 2026

## After this lesson you can

- Pass a model from an action to its view with View(model)
- Declare a view's model type with @model and read it through Model
- Pass a small extra value to a view with ViewData

## Key takeaways

- `return View(model)` runs the view named after the action, in the folder named after the controller, such as `Views/Products/Index.cshtml`.
- `@model` at the top of a view names the model's type; `Model` is the object the action passed.
- Because the view knows its model's type, a misspelled property is a build error, not a blank page.
- Use the model for the page's real data, and `ViewData` only for small extras, such as the page's title.

A **view** is a `.cshtml` file: HTML with C# mixed in, written in a syntax called **Razor**. The controller decides *what* to show; the view decides *how* it looks.

## Which view runs

`return View(...)` looks for a view with the **action's name**, in a folder with the **controller's name**:

| Controller and action | View file |
|---|---|
| `ProductsController.Index` | `Views/Products/Index.cshtml` |
| `ProductsController.Details` | `Views/Products/Details.cshtml` |
| `HomeController.Privacy` | `Views/Home/Privacy.cshtml` |

If it isn't there, ASP.NET Core looks in `Views/Shared` next. (In Visual Studio, right-click inside an action and choose **Add View...** to make the file in the right place.)

## The model: one object from the action to the view

In the action, pass the data to `View`:

```csharp
// GET /Products
public IActionResult Index()
{
    List<Product> products = productDao.GetAll();
    return View(products);
}
```

At the top of the view, say what type the model is with **`@model`**, then use it through the **`Model`** property:

```cshtml
@model List<Product>
@{
    ViewData["Title"] = "Products";
}

<h1>Products</h1>
<p>Northwind sells @Model.Count products.</p>

<table class="table table-striped">
    <thead>
        <tr>
            <th>Product</th>
            <th class="text-end">Price</th>
            <th class="text-end">In stock</th>
        </tr>
    </thead>
    <tbody>
        @foreach (Product product in Model)
        {
            <tr>
                <td>@product.ProductName</td>
                <td class="text-end">@product.UnitPrice?.ToString("C")</td>
                <td class="text-end">@product.UnitsInStock</td>
            </tr>
        }
    </tbody>
</table>
```

Save it as `Views/Products/Index.cshtml` and go to `/Products`. Razor runs the C# and sends plain HTML; the first rows look like this:

```html
<h1>Products</h1>
<p>Northwind sells 77 products.</p>
...
<tr>
    <td>Alice Mutton</td>
    <td class="text-end">$39.00</td>
    <td class="text-end">0</td>
</tr>
<tr>
    <td>Aniseed Syrup</td>
    <td class="text-end">$10.00</td>
    <td class="text-end">13</td>
</tr>
```

Two different words, and both matter:

- **`@model`** (small m) goes once, at the top. It tells Razor the model's **type**.
- **`Model`** (capital M) is the model **itself**, the object the action passed.

Because the view knows the type, Visual Studio offers `Model.Count`, `product.ProductName` and the rest as you type, and a misspelled property is a build error, not a blank page.

`Product` needs no `using` in the view: the project's `Views/_ViewImports.cshtml` already has `@using NorthwindWeb.Models` for every view.

## One product

The details page gets one `Product`:

```cshtml
@model Product
@{
    ViewData["Title"] = Model.ProductName;
}

<h1>@Model.ProductName</h1>

<p>Price: @Model.UnitPrice?.ToString("C")</p>
<p>In stock: @Model.UnitsInStock</p>
```

Save it as `Views/Products/Details.cshtml`, and go to `/Products/Details/7` for Uncle Bob's Organic Dried Pears, $30.00.

## ViewData: small extras

A view has one model. For a small extra value, such as the text of a search box or the page's title, there's **`ViewData`**: a dictionary that the action and the view share for one request.

```csharp
ViewData["SearchText"] = name;
```

```cshtml
@{
    string? searchText = ViewData["SearchText"] as string;
}
<p>You searched for "@searchText".</p>
```

`ViewData` holds `object` values, so the view has to convert them back to their type (`as string`), and a misspelled key gives `null` instead of a build error. Use the model for the page's real data, and `ViewData` only for extras. The views above already use it for one: `ViewData["Title"]` sets the browser tab's title, as you'll see in *Layouts and _ViewStart*.

## Common problems

| What you see | What to do |
|---|---|
| `The model item passed into the ViewDataDictionary is of type '...', but this ViewDataDictionary instance requires a model item of type '...'` | The action passed one type and `@model` names another. Make them match. |
| `NullReferenceException` on `Model` | The action returned `View()` without the model. Pass it: `View(products)`. |
| `The type or namespace name 'Product' could not be found` | The model's namespace isn't in `_ViewImports.cshtml`. Add `@using NorthwindWeb.Models`. |

## Check yourself

3 questions to try on the lesson page.

## So what

`View(model)` in the action, `@model` and `Model` in the view: that handshake is how every page gets its data. The controller fetches, the view shows, and the model is what passes between them.

## Key terms

- .cshtml File
- @model
- Strongly Typed View
- ViewData

## Cheat sheets

- [Passing a Model to a View](https://www.ask-codey.com/cheat-sheets/razor-views-passing-a-model-to-a-view-cheat-sheet)

Source: https://www.ask-codey.com/lessons/razor-views-passing-a-model-to-a-view
