Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating a Better Master Page

0.00/5 (No votes)
13 Nov 2007 2  
Merging �MasterPage� with �BasePage�

Introduction

In this article, I am going to explain how to merge BasePage classes with MasterPage so that you can control UIs and page functionalities.

MasterPage

MasterPage is a new technique in ASP.NET 2.0 that is very helpful in maintaining full web application design in generic places. Using this, we can change the complete look and feel of the application within a short duration. Normally, we keep our layout designs in MasterPage and all other pages will extend the UI from it.

Click here to see more about MasterPages.

Is it Inheritance?

Even though we are extending the UI from MasterPage, it's not an inheritance concept. MasterPage is just providing the content place-holder to enable the extended page to provide the page-specific UI.

Creating a Simple Example

Step 1

Create a MasterPage with some header content, footer content and place holder content, as below.

MasterPage.Master
<%@ Master Language="C#" AutoEventWireup="true" 
    CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>

<!DOCTYPE html PUBLIC 
    "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <h3>Header Contents</h3><hr />
        <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
        </asp:contentplaceholder>
     <hr /><h3>Footer Contents</h3>
    </div>
    </form>
</body>
</html>

Step 2

Create a WebPage and refer the MasterPage using the page directive, as below.

Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" 
    MasterPageFile="~/MasterPage.master"  
    CodeFile="Default.aspx.cs" Inherits="_Default" %>
<asp:Content runat="server" ContentPlaceHolderID="ContentPlaceHolder1" 
    ID="PageContent">
<b>Content</b>
</asp:Content>

Step 3

Run the sample. You can see the following output with header, footer and page-specific content. This is how we are placing generic UI content (header, footer) into a generic place.

Output: Default.aspx (Rendered using "MasterPage")
Screenshot - MasterPageOutPut.jpg

Disadvantages of MasterPage

MasterPage is just for the UI extension. You cannot achieve actual inheritance advantages using that. For example, using inheritance you can have generic methods and properties in the base class that can be used by all the derived web forms, i.e. you can have logging, exception handling, session handling in base class and these can be used by all the web forms.

BasePage

What is BasePage?

BasePage is just a concept that was followed by many developers before ASP.NET 2.0. It has also been called by different names like "PageBase," "WebPageBase" and many more. The concept of BasePage is really simple: to create a class that is inherited from System.Web.UI.Page and use this class as a base class for all the web forms. Unfortunately, you will not get all the UI from the base class to a derived class in web form. This is because, in ASP.NET, the UI is built using the Context approach. The inheritance will not help to render the base class UI, even though you can get the BasePage UI by adding some code in RenderChild or in the Render method of the base class.

Creating a Simple Example

Step 1

Create two user controls (*.ascx) for the header and footer, as below.

HeaderControl.ascx
<%@ Control Language="C#" AutoEventWireup="true" 
    CodeFile="HeaderControl.ascx.cs" Inherits="HeaderControl" %>
<h3>Header Content</h3><hr />
FooterControl.ascx
<%@ Control Language="C#" AutoEventWireup="true" 
    CodeFile="FooterControl.ascx.cs" Inherits="FooterControl" %>
<hr /><h3>Footer Content</h3>

Step 2

Just create a class and inherit it from System.Web.UI.Page. Then add some generic methods like Logging, Session, etc. Override the Render method and add the code like below.

BasePage.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
//Properties: Logger,CurrentSession is just created for the example purpose


/// <summary>

/// Inherit all the web pages from this class, 

/// this will add Generic UI, and Generic functions to the web page

/// </summary>

public class BasePage:System.Web.UI.Page
{
    public BasePage()
    {
        //

        // TODO: Add constructor logic here

        //


        _Logger = new Logger();
    }
    protected override void Render(HtmlTextWriter writer)
    {
        Control header = this.LoadControl("HeaderControl.ascx");
        Control footer = this.LoadControl("FooterControl.ascx");
        
        //Adding at the first the position (Header)

        this.Form.Controls.AddAt(0, header);

        //Adding at the Last position(Footer)

        this.Form.Controls.AddAt(this.Form.Controls.Count, footer);
        

        base.Render(writer);
    }

    private Logger _Logger;

    //note that Derived class cannt create instance of it

    //this is also a kind of controling

    public Logger Logger
    {
        get { return _Logger; }
        
    }

    private SessionData _CurrentSession;

    public SessionData CurrentSession
    {
        get { return _CurrentSession; }
        set { _CurrentSession = value; }
    }

}
Logger Class
/// <summary>

/// This class is responsible for logging

/// Please note that you can also use Microsoft 

/// Enterprise Library Logging Block

/// </summary>

public class Logger
{
    public void LogWarning(object Message)
    {
        //write some logic here

    }
    public void LogError(object Message)
    {
        //write some logic here

    }
    public void LogTrace(object Message)
    {
        //write some logic here

    }
}
Session Handling Class
public class SessionData
{
    public int UserId
    {
        get 
        { 
            return int.Parse(
                HttpContext.Current.Session["UserId"].ToString());
        }
        set { HttpContext.Current.Session["UserId"] = value; }
    }

    public List<int> ItemIds
    {
        get { return (List<int>)HttpContext.Current.Session["Items"]; }
        set { HttpContext.Current.Session["Items"] = value; }
    }
    
}

Note: the above session handling and logger classes are just added for explanatory purposes. You can also add any generic elements with respect to your project.

Step 3

Create a web form and change the base class name from System.Web.UI.Page to BasePage.

Default2.aspx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Default2 : BasePage
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
}

Result

Now we are able to render the UI from the base class, as with MasterPage. We are also using methods and properties provided by the base class. So really, we can control our UI and the functionalities of the application from a single place.

Output: Default2.aspx (Rendered using "BasePage")
Screenshot - BasePageOutput.jpg

Disadvantages of BasePage

This is not really a proven technique, but still, I've already implemented it in many client places and it's really working well, even for huge requests. Also, we are adding the controls only inside the <form> tag, so updating <head> tag elements like style sheet references and page titles is a bit difficult.

Merging BasePage and MasterPage

It's easy to merge these two techniques, BasePage and MasterPage. Just add the following code to the BasePage constructor and remove the code that we added in the Render method, so now the BasePage will look like below.

Changing BasePage.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
//Properties: Logger,CurrentSession is just created for the example purpose


/// <sumary>

/// Inherit all the web pages from this, 

/// this will add Generic UI for the Application

/// </summary>

public class BasePage:System.Web.UI.Page
{
    public BasePage()
    {
        //

        // TODO: Add constructor logic here

        //


        _Logger = new Logger();
        this.MasterPageFile = "MasterPage.Master";
    }
  
    private Logger _Logger;

    //note that Derived class cannt create instance of it

    //this is also a kind of controling

    public Logger Logger
    {
        get { return _Logger; }
        
    }

    private SessionData _CurrentSession;

    public SessionData CurrentSession
    {
        get { return _CurrentSession; }
        set { _CurrentSession = value; }
    }

}

Try to access the generic methods that are provided by BasePage from the derived web page.

Intellisense of the Default2.aspx.cs File, which is Inherited from BasePage
Screenshot - VS2005IntelScreen.jpg

In a single place -- I would like to call it MasterBasePage-- we can control the following things of the web application:

  • UI layout [from MasterPage]
  • Session handling [from BasePage]
  • Project-specific properties [from BasePage]
  • Logging [from BasePage]
  • And so on�

Issues in Visual Studio 2005

Here we are not using MasterPage page directive attributes in derived pages, so Visual Studio 2005 is giving some error in the designer to use the content place holder. Right now, I'm looking into this issue.

History

  • 14 November, 2007 -- Original version posted

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here