ASP.NET Tweeks (Part 1): PageBase
Modularity is the heart of any application. This is the first of a multi-part part series of Tweeks that you can use while writing a modular ASP.NET application. The first module on the list is the use of a PageBase object. The PageBase class derives from the System.Web.UI.Page class, it should exist in an external components library, and it should replace the System.Web.UI.Page object that every .aspx page derives from. If the PageBase class, as well as any custom controls, are placed in the web application itself you will run into several issues (especially while debugging) that worst case can cause Visual Studio to crash. Never place the PageBase class or custom controls in the App_Code folder.
The concept of using a PageBase class has been around for a very long time, but never really got a face lift with the advent of master pages. Master pages took over some of the functionality of what a typical PageBase class would perform, and required the duplication of common access business tier code. The next part of this series covers Business Abstraction, to eliminate the duplication of code and to provide a single method of accessing the business tier. Here is a sample set of PageBase classes w/ direct Business access. 1 for Web Forms, and 1 for Web Content Forms (based on a master page):
using System;
using System.Web.UI;
using BusinessFacade;
/// <summary>
/// Summary description for PageBase.
/// </summary>
/// <typeparam name="TMaster">The master page being used.</typeparam>
public class PageBase<TMaster> : PageBase
where TMaster : MasterPage
{
/// <summary>
/// Gets the hard typed master page.
/// </summary>
public new TMaster Master
{
get { return (TMaster)base.Master; }
}
}
/// <summary>
/// Summary description for PageBase.
/// </summary>
public class PageBase : Page
{
private CommonDataBF _commonDataBF;
private UserManagementBF _userManagementBF;
/// <summary>
/// Gets a <see cref="CommonDataBF"/> business object.
/// </summary>
public CommonDataBF CommonData
{
get
{
if (_commonDataBF == null)
{
_commonDataBF = new CommonDataBF();
}
return _commonDataBF;
}
}
/// <summary>
/// Gets a <see cref="UserManagementBF"/> business object.
/// </summary>
public UserManagementBF UserManagement
{
get
{
if (_userManagementBF == null)
{
_userManagementBF = new UserManagementBF();
}
return _userManagementBF;
}
}
}
To use this, modify the declaration of the code behind page class to derive from this class. Use the standard PageBase class for normal page forms, and use the generic PageBase class for page content forms (pages that use a master page). Master pages don't normally need this same type of handling, as there should be a single master page that all other master pages cascade from. However, you will want your master pages to implement interfaces, which makes it easier to pass-through public properties and methods. This is an interface that I use, which is inherited by all master pages:
/// <summary>
/// Summary description for IMasterPage.
/// </summary>
public interface IMasterPage
{
/// <summary>
/// Gets the <see cref="MembershipUser"/> object for the currently logged in user.
/// </summary>
MembershipUser User { get; }
/// <summary>
/// Gets the identifier of the currently logged in user.
/// </summary>
Guid UserId { get; }
/// <summary>
/// Gets or sets the suffix to be added to the HTML page title.
/// </summary>
string PageTitleSuffix { get; set; }
}
The parent master obviously is the source of these properties and methods, but here is the pass-through code of a child master page that implements it:
public partial class UserMaster : MasterPage, IMasterPage
{
/// <summary>
/// Gets the <see cref="MembershipUser"/> object for the currently logged in user.
/// </summary>
public MembershipUser User
{
get { return ((IMasterPage)base.Master).User; }
}
/// <summary>
/// Gets the identifier of the currently logged in user.
/// </summary>
public Guid UserId
{
get { return ((IMasterPage)base.Master).UserId; }
}
/// <summary>
/// Gets or sets the suffix to be added to the HTML page title.
/// </summary>
public string PageTitleSuffix
{
get { return ((IMasterPage)base.Master).PageTitleSuffix; }
set { ((IMasterPage)base.Master).PageTitleSuffix = value; }
}
}
When the master page interfaces and PageBase class are coupled together, you end up with a very nice and easy to use interface with very little duplication of code (the implementation of the master page interfaces on child masters). You can completely eliminate all duplication of code by declaring a MasterPageBase for each master page that has child master pages, but it may be more difficult to manage and not prudent to do. Additionally, if you are using user controls, as you should be, interfaces and a UserControlBase class are the best way to pass information back and forth between the page and controls, and even from control to control when using nested user controls.