Working with Master Pages in ASP.NET MVC 2

Exclusive offer: get 50% off this eBook here
ASP.NET MVC 2 Cookbook

ASP.NET MVC 2 Cookbook — Save 50%

Over 70 clear and incredibly effective recipes to get the most out of the many tools and features of the ASP.NET MVC framework

$29.99    $15.00
by Andrew Siemer Richard Kimber | January 2011 | .NET Cookbooks Web Development

Master pages are a very important part of any large-scale site. They allow you to easily manage the boilerplate code that every page in your site uses. This might encompass features such as navigational items, header and footer layout, basic layout, and so on. In this article by Andrew Siemer and Richard Kimber, authors of ASP.NET MVC 2 Cookbook, we will discuss how to create and use master pages to control application-wide formatting. We will also take a look at how to employ a base page, to control which master page is used. Then we will see how to pass data from the view to the master page. Specifically we will cover:

  • How to create a master page
  • Determining the master page in the ActionResult
  • Controlling which master page is used with a view base class
  • Setting the master page from a controller base class
  • Passing data to the master page

 

ASP.NET MVC 2 Cookbook

ASP.NET MVC 2 Cookbook

A fast-paced cookbook with recipes covering all that you wanted to know about developing with ASP.NET MVC

  • Solutions to the most common problems encountered with ASP.NET MVC development
  • Build and maintain large applications with ease using ASP.NET MVC
  • Recipes to enhance the look, feel, and user experience of your web applications
  • Expand your MVC toolbox with an introduction to lots of open source tools
  • Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible
        Read more about this book      

(For more resources on .NET, see here.)

How to create a master page

In this recipe, we will take a look at how to create a master page and associate it with our view. Part of creating a master page is defining placeholders for use in the view. We will then see how to utilize the content placeholders that we defined in the master page.

How to do it...

  1. Start by creating a new ASP.NET MVC application.
  2. Then add a new master page to your solution called Custom.Master. Place it in the Views/Shared directory.
  3. Notice that there is a placeholder already placed in the middle of our page. Let's wrap that placeholder with a table. We will put a column to the left and the right of the existing placeholder. Then we will rename the placeholder to MainContent.

    Views/Shared/Custom.Master:

    <table>
    <tr>
    <td>

    </td>
    <td>
    <asp:ContentPlaceHolder ID="ContentPlaceHolder1"
    runat="server"></asp:ContentPlaceHolder>
    </td>
    <td>

    </td>
    </tr>
    </table>

  4. Next, we will copy the placeholder into the first and the third columns.

    Views/Shared/Custom.Master:

    <table>
    <tr>
    <td>
    <asp:ContentPlaceHolder ID="ContentPlaceHolder1"
    runat="server"></asp:ContentPlaceHolder>
    </td>
    <td>
    <asp:ContentPlaceHolder ID="MainContent"
    runat="server"></asp:ContentPlaceHolder>
    </td>
    <td>
    <asp:ContentPlaceHolder ID="ContentPlaceHolder2"
    runat="server"></asp:ContentPlaceHolder>
    </td>
    </tr>
    </table>

  5. Next, we need to add a new action to the HomeController.cs file, from which we will create a new view. Do this by opening the HomeController.cs file, then add a new action named CustomMasterDemo.

    Controllers/HomeController.cs:

    public ActionResult CustomMasterDemo()
    {
    return View();
    }

  6. Then right-click on the CustomerMasterDemo and choose AddView, and select the new Custom.Master page that we created. Next, you need to change the ContentPlaceHolderID box to show the center placeholder name ContentPlaceHolder2. Then hit Add and you should see a new view with four placeholders.

    Views/Home/CustomMasterDemo.aspx:

    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
    runat="server">
    <h2>Custom Master Demo</h2>
    </asp:Content>

    <asp:Content ID="Content2" ContentPlaceHolderID="head"
    runat="server">
    <meta name="description" content="Here are some keywords for our
    page description.">
    </asp:Content>

    <asp:Content ID="Content3"
    ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <div style="width:200px;height:200px;border:1px solid #ff0000;">
    <ul>
    <li>Home</li>
    <li>Contact Us</li>
    <li>About Us</li>
    </ul>
    </div>
    </asp:Content>

    <asp:Content ID="Content"
    ContentPlaceHolderID="ContentPlaceHolder2" runat="server">
    <div style="width:200px;height:200px;border:1px solid #000000;">
    <b>News</b><br/>
    Here is a blurb of text on the right!
    </div>
    </asp:Content>

  7. You should now see a page similar to this:

How it works...

This particular feature is a server-side carry over from web forms. It works just as it always has. Before being sent down to the client, the view is merged into the master file and processed according to the matching placeholder IDs.

Determining the master page in the ActionResult

In the previous recipe, we took a look at how to build a master page. In this recipe, we are going to take a look at how to control what master page to use programmatically. There are all sorts of reasons for using different master pages. For example, you might want to use different master pages based on the time of day, if a user is logged in or not, for different areas of your site (blog, shopping, forum, and so on).

How to do it...

  1. We will get started by first creating a new MVC web application.
  2. Next, we need to create a second master page. We can do this quickly by making a copy of the default master page that is provided. Name it Site2.Master.
  3. Next, we need to make sure we can tell these two master pages apart. The easiest way to do this is to change the contents of the H1 tag to say Master 1 and Master 2 in each of the master pages.
  4. Now we can take a look at the HomeController. We will check if we are in an even or odd second and based on that we can return an even or odd master page. We do this by specifying the master page name that we want to use when we return the view.

    Controllers/HomeController.cs:

    public ActionResult Index()
    {
    ViewData["Message"] = "Welcome to ASP.NET MVC!";

    string masterName = "";

    if (DateTime.Now.Second % 2 == 0)
    masterName = "Site2";
    else
    masterName = "Site";
    return View("Index", masterName);
    }

  5. Now you can run the application. Refreshing the home page should alternate between the two master pages now and then. (Remember that this is based on the second and is now just a pure alternating page scheme.)

How it works...

This method of controlling which master page is used by the view is built into the MVC framework and is the easiest way of performing this type of control. However, having to dictate this type of logic in every single action would create quite a bit of fluff code in our controller. This option might be appropriate for certain needs though!

ASP.NET MVC 2 Cookbook Over 70 clear and incredibly effective recipes to get the most out of the many tools and features of the ASP.NET MVC framework
Published: January 2011
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on .NET, see here.)

Controlling which master page is used with a view base class

In this recipe, we are going to take a look at another approach for setting which master page is used by the view. Specifically, we are going to create a base class that can be inherited by our view pages. In the base class we can then override the OnPreInit method, inside of which we can easily control the master page that is used by the view.

How to do it...

  1. Start by creating a new MVC project.
  2. Next, create a copy of the existing master page and call it Site2.Master.
  3. Change the H1 text to show Master 1 and Master 2, so that we can easily tell which master page is being used.
  4. Then we need to create a new class in our Models folder called BaseViewPage.cs.
  5. In the new base class that we are creating, we need to inherit from System.Web.Mvc.Viewpage. Then we need to define a method that overrides the framework's OnPreInit method. Inside of our method, we will build up some logic to check if we are in an even or odd second when the page loads. Based on the result of our test, we will load the Site2.master file or Site.master file.

    Models/BaseViewPage.cs:

    public class BaseViewPage : System.Web.Mvc.ViewPage
    {
    protected override void OnPreInit(EventArgs e)
    {
    if(DateTime.Now.Second%2==0)
    Page.MasterPageFile = "~/Views/Shared/Site2.Master";
    else
    Page.MasterPageFile = "~/Views/Shared/Site.Master";
    base.OnPreInit(e);
    }
    }

  6. For this logic to get executed, we need to set our Index view to inherit from our new base class instead of inheriting from System.Web.Mvc.ViewPage.

    Views/Home/Index.aspx:

    <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="MvcApplication1.Models.BaseViewPage" %>
    ...

  7. Now you can run your application. Refreshing the home page should show the master pages being switched now and then, based on the second that the page is being loaded.

How it works...

Because our view was set to inherit from our custom base class and our base class catches the OnPreInit event, we are able to set the master page prior to the page being built. This is important as you can toggle the master page that a view uses after it has started being rendered! Now all we need to do is use our base class for all of our views (a good idea even if you don't yet need it, as it will provide you with an added point of extensibility).

Setting the master page from a controller base class

In this recipe, we will take a look at how to control our master pages at a higher level. We will create a controller base class. In the controller base class, we will then take control of which master page is used by the views that are controlled by controllers that inherit from our shiny new base class.

How to do it...

  1. The first step is to create a new MVC application.
  2. Then copy the existing master page and create a new master page called Site2.master.
  3. Next, change the H1 text for each of the master pages to Master 1 and Master 2 accordingly.
  4. Now, we can create a BaseController class in the Models folder. This class will inherit from Controller. Then we will set the BaseController to override the OnActionExecuted method. In this method, we will get an instance of the current ViewResult from the passed-in context. We need to check to make sure that the instance is not null. Then we will perform some logic to check if we are in an even or odd second, and set the corresponding master page based on the results of that test. Then we return the context to the pipeline.

    Models/BaseController.cs:

    public class BaseController : Controller
    {
    protected override void OnActionExecuted(
    ActionExecutedContext filterContext)
    {
    var action = filterContext.Result as ViewResult;
    if (action != null)
    {
    if (DateTime.Now.Second % 2 == 0)
    action.MasterName = "Site2";
    else
    action.MasterName = "Site";
    }
    base.OnActionExecuted(filterContext);
    }
    }

  5. With our BaseController created we can wire it up to our HomeController by having our HomeController inherit the new BaseController.

    Controllers/HomeController.cs:

    public class HomeController : BaseController

  6. Now you can run the application and refresh the home page. You should see the Site and Site2 master pages being used now and then.

How it works...

This is just another example of a hook that we can attach to affect how the MVC application works. In this case, we are hooking into the OnActionExecuted event. This event is raised prior to the view being rendered and after the action method is executed—which means we still have time to alter the master page that is used by the current view.

Passing data to the master page

In this recipe, we are going to take a look at how to pass data down to the master page. While we could pass data from a normal ActionResult to the view via the ViewData dictionary and then have the MasterPage use that data, we won't as that creates a lot of redundant code spread out over multiple actions in the controller. We could alleviate some of this action code and move it up to the OnActionExecuted method in our controller. However, if our master page is shared across multiple controllers, then this too wouldn't be a good solution. For that reason, we will instead create a controller base class and use that for creating the data for our master page.

How to do it...

  1. The first step is to create a new MVC application.
  2. Next, we will create a controller base class called BaseController. In this base controller, we will initiate a list of data for navigational purposes.

    Models/BaseController.cs:

    public class BaseController : Controller
    {
    public BaseController()
    {
    List<string> manufacturers = new List<string>();
    manufacturers.Add("Ford");
    manufacturers.Add("Toyota");
    manufacturers.Add("Chevy");
    manufacturers.Add("Dodge");
    manufacturers.Add("Nissan");
    manufacturers.Add("Mazda");
    manufacturers.Add("Audi");

    ViewData["manufacturers"] = manufacturers;
    }
    }

  3. Next, we will alter our HomeController to inherit from our new BaseController.

    Controllers/HomeController.cs:

    public class HomeController : BaseController

  4. Now that our data is being created and passed down to every view that is created from this controller, we need to update our master page to take advantage of this data.

    Views/Shared/Site.Master:

    ...
    <div id="main">
    <%string menu = "";
    if (ViewData["manufacturers"] != null)
    {
    StringBuilder sbMenu = new StringBuilder();
    List<string> manufacturers = ViewData["manufacturers"] as
    List<string>;
    foreach (string item in manufacturers)
    {
    sbMenu.Append(item + " - ");
    }

    menu = sbMenu.ToString().Substring(0,
    sbMenu.ToString().Length - 3);
    }
    %>
    <%: menu %>
    ...
    </div>
    ...

  5. Now you can browse to your Index and About views and you should see a new listing of auto manufacturers, which represents a navigation menu, without links. If you browse to the login or registration views, which use the Account controller, the navigation menu will disappear.

How it works...

To achieve this, we have essentially injected data that is required by our master page into the controller pipeline by inserting a controller base class. As long as our controller inherits from the base class, the ViewData will contain the navigation data. This helps us to centralize such logic and can obviously be taken in many different directions.

Summary

In this article we covered:

  • How to create a master page
  • Determining the master page in the ActionResult
  • Controlling which master page is used with a view base class
  • Setting the master page from a controller base class
  • Passing data to the master page

Further resources on this subject:


ASP.NET MVC 2 Cookbook Over 70 clear and incredibly effective recipes to get the most out of the many tools and features of the ASP.NET MVC framework
Published: January 2011
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Andrew Siemer

Andrew Siemer is currently the enterprise architect at OTX Research. He has worked as a software engineer, enterprise architect, trainer, and author since 1998 when he got out of the Army. Andrew has consulted with many companies on the topics of e-commerce, social networking, and business systems. To name a few, he has worked with eUniverse (AllYouCanInk.com), PointVantage (MyInks.com), Callaway Golf (CallawayConnect.com), Guidance Software (GuidanceSoftware.com), and Intermix Media (Grab.com, AmericanIdol.com, FoxSports.com, FlowGo.com). In addition to his daily duties he also offers various classes in .NET, C#, and other web technologies to local students in his area as well as blogging in his *free* time.

Richard Kimber

Richard Kimber has been working with web technologies for over 15 years. Primarily ASP.NET developer, Richard has worked in a broad range of development environments, from the financial services industry to new media and marketing. He now runs a web and mobile consultancy company called Dogma Creative with his wife Katie.

Books From Packt


.NET Compact Framework 3.5 Data Driven Applications
.NET Compact Framework 3.5 Data Driven Applications

DotNetNuke 5.4 Cookbook
DotNetNuke 5.4 Cookbook

NHibernate 3.0 Cookbook
NHibernate 3.0 Cookbook

Microsoft Azure: Enterprise Application Development
Microsoft Azure: Enterprise Application Development

Microsoft Windows Workflow Foundation 4.0 Cookbook
Microsoft Windows Workflow Foundation 4.0 Cookbook

WCF 4.0 Multi-tier Services Development with LINQ to Entities
WCF 4.0 Multi-tier Services Development with LINQ to Entities

Mastering phpMyAdmin 3.3.x for Effective MySQL Management
Mastering phpMyAdmin 3.3.x for Effective MySQL Management

Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications
Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications


Your rating: None Average: 5 (1 vote)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
6
T
y
Z
i
k
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software