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
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 asViews/Products/Index.cshtml.@modelat the top of a view names the model's type;Modelis 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
ViewDataonly 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:
// 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:
@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:
<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:
@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.
ViewData["SearchText"] = name;
@{
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