Friday, May 4, 2012

Strongly Typing Asp.Net MVC Master/Layout Pages

When developing Asp.Net MVC pages it is best practice to strongly type the views so that data passed from the controller can be accessed in a controlled and safe manner.

Strongly Typing Views

This is achieved in a couple of ways depending on which view engine is being used. When adding the view it is possible to choose the data type of the model that is to be used within the view.

Aspx view engine

If you choose to use the aspx view engine then the model class can be selected in the drop down and this will generate the correct markup to strongly type the model to the selected class.

image

The standard aspx view engine employs the markup style notation for defining the type of the Model.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/View.Master" Inherits="System.Web.Mvc.ViewPage<MvcApplication1.Models.CustomerViewModel>" %>

Razor view engine


The razor view engine employs a much cleaner approach to typing the model. Again the class for the model can be selected in the drop down in the Add View dialog, like the one shown below.


image


This will generate code similar to that shown below, that uses the new @model razor notation to type the view to the specified class.

@model MvcApplication1.Models.CustomerViewModel

Master / Layout pages


There are a number of reasons that you may want to strongly type the model on the master page, as doing this is preferable to using TempData or ViewData directly. Depending on the model semantics that you are building it may be that all pages need to build a top level menu, however this is built from dynamic data. In this case it would make sense to make this data available in the model, and also add the code to generate the menu to the layout or master page, as it is not desirable to replicate this on multiple pages.


Anyone that has created a new layout / master page will realise that when adding a layout or master view you are not asked about strongly-typing the view. However just because you are not asked doesn’t mean that it isn’t possible!


The usual method of adding a new layout or master page is to choose the add new item, menu item and this will allow you to choose the type of view to add, and generate the view from the visual studio file template.


With a couple of tweaks to the generated code it is possible to strongly-type the master/layout page and get all the benefits that this brings.


Standard inheritance rules apply here!


As long as you follow basic inheritance rules strongly typing the model on the master/layout page is perfectly safe.


The thing to remember is that all models used on views that use the master/layout page must derive from the model defined on the master/layout page. Obvious really isn’t it!


So for example using the following classes


image


It is possible to strongly type the master/layout views to use the BaseViewModel class. Allowing the base classes Message property to be used directly within the master/layout page.


Aspx view engine


Utilize the System.Web.Mvc.ViewMasterPage<T> generic base class to specify the type of the model.

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MvcApplication1.Models.BaseViewModel>" %>
<!DOCTYPE html>
<
html>
<
head runat="server">
<
title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
</
head>
<
body>
<
div>
<
asp:ContentPlaceHolder ID="MainContent" runat="server">
<%: Model.Message %>
</asp:ContentPlaceHolder>
</
div>
</
body>
</
html>

Razor view engine


Utilize the same @model notation as used in the view page to specify the type of the model.

@model MvcApplication1.Models.BaseViewModel
<!DOCTYPE html>
<
html>
<
head>
<
meta charset="utf-8" />
<
title>@ViewBag.Title</title>
<
link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<
script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<
script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
</
head>
<
body>
<
div class="message">
<
p>@Model.Message</p>
</
div>
@RenderBody()
</body>
</
html>

Summary


That's all there is to it! Have fun changing all your master/layout pages to be strongly typed! Obviously if the layout/master page is only being used for layout then there is no benefit in doing this. However with the real life pages that I have experience in building the master/layout pages nearly always need so data which could be on the model.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. But where and when is the model for master layout page instantiated?

    ReplyDelete
  3. The model for the master layout page is the same model that you set for the View, that is the whole point.

    The model on the master should be a base type of the View Model, then when you set the Model in your Controller the master layout page will be able to use properties that are available on the base type.

    ReplyDelete