ASP.NET MVC Model: Make a BaseViewModel for your Layouts

September 29th, 2014

If you aren't using ViewModels, start now by creating base classes and realize the flexibility of every view, including layout pages.

One day while I was working with MVC, I had an issue with layouts. I kept getting model issues on my layout pages.

The problem was I had a separate ViewModel for each page and I was using a different ViewModel for my layout page.

So how do you pass a model to a page that is required on your layout pages.

Time to Refactor

This tip is extremely quick, easy, and I guarantee you will remember it when creating a hierarchy of layout pages for a new site. You'll be able to nest any amount of layout pages to any depth and keep your sanity with your ViewModels.

I will use my example from ASP.NET MVC Controllers: Push the envelope and build off of that.

First, create a new class and call it BaseViewModel.

Models/BaseViewModel.cs

using System;
 
namespace ThinController.Models
{
    public class BaseViewModel
    {
        public String PageTitle { get; set; }
        public String MetaKeywords { get; set; }
        public String MetaDescription { get; set; }
    }
}

Of course, this will contain all of your common page data. As you can see, we want each page to contain a Title, Keywords, and a Description to assist Google, or Bing, or whoever is your favorite crawler.

You could add a list of menu items, ad objects, or other classes as well if you have additional properties that are common on every single page.

Next, place the BaseViewModel as your model in your top Layout view.

Views/Shared/_Layout.cshtml (Snippet)

@model ThinController.Models.BaseViewModel
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@Model.PageTitle</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
.
.

The key takeaway here is the top line with the model and the <title> tag.

Now, we have our Faq Page that has a list of FAQ items. Since we already have our FaqViewModel from before, all you need to do is inherit from the BaseViewModel.

Models/FaqViewModel.cs

using System.Collections.Generic;
 
namespace ThinController.Models
{
    public class FaqViewModel : BaseViewModel
    {
        public IEnumerable<Faq> FaqList { get; set; }
    }
}

Lastly, place the FaqViewModel as your model on the Faq Index.cshtml page (which should already be there based on the example).

You shouldn't have to do anything else. Your code should compile and work just as before, but now, you have a common ViewModel for all of your pages.

What exactly is happening?

Since your layout has a ViewModel (using the @model) when rendering, it looks at that first and uses the Razor engine to fill the template as much as possible before rendering the children.

However, the ViewModel that you are passing to the view is a FaqViewModel. The fact is that since the FaqViewModel inherits from the BaseViewModel, all of the properties are available to the Layout view, but the additional properties will be available to the Index.cshtml page when it renders as well.

Pretty slick!

This means you can create pages of master layouts similar to WebForms and not lose any ViewModel goodness. :-)

I hope this helps in your master page layouts on your website.

Does this make sense? Post your comments and questions below.