Strongly Typed Views in MVC

In ASP.NET MVC, we have a couple of options for passing data from a controller to a view:

  • ViewData
  • ViewBag
  • View-specific data model

ViewData

The ViewData  property is on the ControllerBase  which all controllers derive from and is accessible from both a controller and a view. It is of type ViewDataDictionary , which implements IDictionary<string, object> . To pass any piece of information to a view using the ViewData , we simply set the value in an action method:

Then, from within the view, we access the value by using the same key:

ViewBag

The ViewBag  is essentially a wrapper around the ViewData dictionary that uses dynamics to allow us to access the data using properties off of the ViewBag property rather than accessing each value by it’s key name. This property too, is off on the ControllerBase.

Then, from the view, we access the same property:

Both of these approaches allow us to pass in information to a view without creating a new class or adding a property to an existing class, however there are several disadvantages with both approaches:

No standard set of properties that get passed into the view
Since the data is passed into the view using essentially a dictionary, there is no way to enforce/ensure that expected values are provided. As such, if we wanted to use a common _Layout page to display the number of unread messages, the _Layout page would have to read the dictionary using a string-based key and check if an item is returned using that key.

In addition, since ViewData is a Dictionary<string, object> , whenever we read a value, we must first check if it is null, and then try to typecast it into a type that we expect it to be.

No intellisense
When working on the view and need to read a property, you will need to look back at the action method to see what the property was called instead of allowing Intellisense to help you find the property.

No compile time checking of our views
Because the ViewData and ViewBag are just dictionaries, there is no way for the compiler to know if a property being accessed from the view was ever set in the action method. It is only at run-time that the bug will present itself.

—–

A Better Approach

Using strongly-typed views that inherit from a base view model we can avoid the problems I just listed. Having the base view model will give us a common set of properties that _Layout page can depend on, we’ll have Intellisense when reading a property from the model and if we turn on view compilation, we’ll also get compile-time checking.

The Model

/Models/ViewModels/BaseViewModel.cs

Base class that all view models will inherit from:

/Models/ViewModels/Home/IndexViewModel.cs

Derived class that will be used by the Index view:

The Controller

/Controllers/BaseController.cs

Base controller that all controllers will derived from. It contains a protected method that will be used to set the standard BaseViewModel  properties. When calling this method, the caller has the option to provide a page title. Also, note that this method is responsible for retrieving and setting the number of unread messages instead of requiring each action method to set this value.

/Controllers/HomeController.cs

The HomeController  will derive from the BaseController  and call the base method to set the properties of the base view model. The Index action method will only deal with setting additional properties needed by its view.

The View

/Views/Home/Index.cshtml

The view works directly with the view model that is specific for this view and does not have to worry about properties on the base view model. Those properties will be handled by _Layout.cshtml

/Views/Shared/_Layout.cshtml

The _Layout page can now access the properties on the base view model in a strongly-typed way with Intellisense and compile-time checking:

Summary

Using a BaseViewModel  we have a structured way of passing data from the controller to the view. Using a BaseController  allows us to move the logic responsible for setting common properties into one centralize place. From the views we can leverage Intellisense to help us access the correct properties from our model and get compile-time errors whenever we access properties that do not exist in our model.

Leave a Reply

Your email address will not be published. Required fields are marked *