TOC
Views:

Passing data into Views

A View can exist without a Model or any other data from the backend, but in most cases, you need to somehow access data made available by a Controller in your View. Since your View shouldn't have to know about your Controller (as per the rule of separation of concerns), your Controller is responsible for making the data available to the View. There are two main ways of doing this: Either you define a strongly typed Model and then pass it to the View, or you can use the ViewData/ViewBag containers to make data available to the View. Let's discuss these approaches now.

Please notice that there will be a bit of overlap in the information provided by this article and the quick-start article on adding a Model to your project.

Using a (View) Model

Since this technology is called MVC, short for Model-View-Controller, the use of a (View) Model is definitely the cleanest and most common approach for passing data into a View. We'll talk more about the Model later in this tutorial, but for now, just know that it's basically just an object, usually representing something from the real world. You'll also run into the concept of a "View Model" - again, we'll dig deeper into this later on, but to describe it shortly, a View Model is just a Model passed to a View. So it can be something that already exists in your project, like a User or Product object, or a class you specifically define to represent the data you wish to access from your View.

A Model doesn't have to be a complex class though - it could, in theory, be something as simple as a String, an Integer or a DateTime. In other words, anything found in the .NET framework can be used as a Model, but in practice, your Model will usually be a class consisting of at least a couple of properties. So for instance, a Model used to represent a Product could look like this:

public class Product
{
public string Title { get; set; }

public double Price { get; set; }
}

The connection between the Model and the View is made by the Controller - it can take input from the user and turn it into relevant data for the View, e.g. like this:

public IActionResult Details(int id)
{
Product product = new Product()
{
Title = "Toilet Paper",
Price = 1.99
};
return View(product);
}

Notice how I pass the product instance to the View when I call the View() method. Inside the Product/Details View, I can now define the Product class as the Model this View can (and should) expect, using the @model directive, located at the top of your View file:

@model HelloMVCWorld.Models.Product

With that in place, you can now start using your (View) Model and its properties in your View:

@model HelloMVCWorld.Models.Product

<h1>@Model.Title</h1>
Price: @Model.Price

Thanks to the fact that you specify a strong type as the Model of the View, you will get help accessing members of the object through IntelliSense and your code will be validated during the Build process, to make sure that you only use properties/methods found on the Model object.

Dynamic Views

If you don't declare a Model type for your View, using the @model directive, the View will not expect any Model of a specific type to be passed into it, but that doesn't prevent you from actually doing just that and even using the object. This is often referred to as a Dynamic View, and is not used very often, because you lose out on the benefits of IntelliSense support and compile-time check of the properties.

So, you could take the example above and remove the @model directive in the top of the View, and it would still work. In this situation, the Model property would be considered a dynamic object, where you can access properties without the compiler checking for their existence. Of course that also means that if you try to access a non-existing property, page generation will fail during runtime, resulting in a nasty exception. Therefore, dynamic views are not used a lot.

Using the ViewData/ViewBag containers

As an alternative to the strongly typed approach to passing data to a View, you can use the so-called ViewData/ViewBag containers. You can add stuff to them from the Controller and then automatically be able to access the stored data in your Views. It's actually quite easy and you can accomplish almost the same things as if you had used a strongly typed Model. Here's an example:

public IActionResult DetailsViewData(int id)
{
ViewBag.ProductTitle = "Toilet Paper";
ViewBag.ProductPrice = 1.99;
return View();
}

You can now access this data in your View just as easily, thanks to the always-available property called ViewBag:

<h1>@ViewBag.ProducTtitle</h1>
Price: @ViewBag.ProductPrice

The major difference here is that there's no compile-time checking of these properties, and no help from the IntelliSense when writing them. In other words, you could easily misspell a property name and you wouldn't notice until you tried using the View. Therefore you should only use the ViewData/ViewBag for very small amounts of data. However, you should remember that you are free to combine the usage of ViewData/ViewBag with a traditional, strongly typed View.

What's the difference between ViewData and ViewBag?

You will have noticed that I have used two terms for dealing with dynamic view data: The ViewData and ViewBag properties. These actually both refer to the same thing, which is a Dictionary of keys and values (the objects). However, the ViewBag is a DynamicObject representation of the Dictionary, allowing you to access the data as if it were properties of the ViewBag object, instead of entries in a Dictionary. You are free to use both properties interchangeably, since they always refer to the same data, so for comparison, here's an example of how it would look if you used both approaches:

Controller:

public IActionResult DetailsViewData(int id)
{
ViewData["ProductTitle"] = "Toilet Paper";
ViewBag.ProductPrice = 1.99;
return View();
}

View:

<h1>@ViewData["ProducTtitle"]</h1>
Price: @ViewBag.ProductPrice

Notice how I use the ViewData and therefore a Dictionary-based approach for reading and writing the ProductTitle, while I use the object-based dot-notation to access the ProductPrice. That leaves you with a few smaller difference, e.g. the ability to check for the presence of a given key/value in the ViewData collection (using the ContainsKey() method). At the end of the day, you should use the approach that you find most appealing and then stick with it for consistency.

Summary

You can pass data from a Controller to a View using several different approaches, but the recommended one is almost always the strongly typed View, where you define the type of Model that your View can expect. This gives you IntelliSense support and compile-time checking of the properties and methods you try to use.