WEBINAR:
On-Demand
Application Security Testing: An Integral Part of DevOps
Implementing the Page Controller Pattern
ASP.NET automatically provides a Presenter implementation for the Model-View-Presenter pattern through a code-behind file for each ASP.NET page. However, you can extend the implementation by adding your own Page Controller in the form of a base class that the code-behind files inherit.
By default, the code-behind class for an ASP.NET page inherits from the Page class in the System.Web.UI namespace. If you create a suitable base class that inherits from Page, you can use this as the base for your own concrete implementations of the code-behind class. This is useful if some or all of your pages require common functionality.
The base class can also perform some of the tasks of a Page Controller by handling the
Page_Init or
Page_Load events. For example, code in the
Page_Load event can select a View to display at runtime for a page, allowing a single page to change its content based on some external condition such as a value in the query string.
By default, the code-behind class for an ASP.NET page inherits from the Page class in the System.Web.UI namespace.
|
|
The example application uses a base class named PageControllerBase (in the
App_code folder), which inherits from System.Web.UI.Page and exposes three values that the concrete classes that inherit from it can access. These values are a reference to the partial View (a user control) to load and display, the name of the View, and a string value to display when no View is specified:
// base class for TransferPage2 and TransferPage3
// implements common tasks and can call method(s)
// in the concrete page class implementations
public class PageControllerBase : Page
{
// values that will be available in page class
protected UserControl displayView = null;
protected String displayViewName = String.Empty;
protected String noViewSelectedText = "No View Selected";
...
The PageControllerBase class handles the
Page_Load event to get the name of the View to display from the query string, and then attempts to create an instance of the appropriate user control for the concrete page code to access. At the end of the
Page_Load event handler, the code calls a method named
PageLoadEvent, passing in the values of the sender and EventArgs originally received as parameters:
protected void Page_Load(Object sender, System.EventArgs e)
{
// get name of view (UserControl) to show in the page
displayViewName = Context.Request.QueryString["view"];
if (displayViewName != null && displayViewName !=
String.Empty)
{
try
{
// load view from ASCX file
displayView = (UserControl)
Page.LoadControl(displayViewName + ".ascx");
}
catch { }
}
// call concrete page class method
PageLoadEvent(sender, e);
}
Every page that inherits from this base class must implement the
PageLoadEvent method. To ensure that this is the case, the PageControllerBase class declares a virtual method that each concrete page implementation must override:
// define method that concrete page classes must implement
// and will be called by this base class after Page_Load
virtual protected void PageLoadEvent(Object sender, System.EventArgs e)
{
// overridden in concrete page implementation
}
The example application contains two pages, named
TransferPage2.aspx and
TransferPage3.aspx that inherit from the PageControllerBase class. The code in the overridden
PageLoadEvent methods is the same in both pagesit is only the View (the ASPX UI) that differs. However, they could be completely different if required, although all inheriting page should make some use of the common functionality of the PageControllerBase class (or there is no point in inheriting from it!). Here's the
PageLoadEvent code used in both pages:
public partial class TransferPage2 : PageControllerBase
{
// override virtual method in PageControllerBase class
protected override void PageLoadEvent(Object sender,
System.EventArgs e)
{
// use values that were set in base class Page_Load event
if (displayView != null)
{
pageTitleElement.Text = "Displaying view '" +
displayViewName + "'";
pageHeadingElement.InnerHtml = "Displaying view '" +
displayViewName + "'";
PlaceHolder1.Controls.Add(displayView);
}
else
{
pageHeadingElement.InnerHtml = noViewSelectedText;
}
// display actual URL of currently executing page
 | |
Figure 7. The CityList View: The figure shows two differing views of the same page. |
lblActualPath.Text = Request.CurrentExecutionFilePath;
String qs = Request.QueryString.ToString();
if (qs != null && qs != String.Empty)
{
lblActualPath.Text += '?' + qs;
}
}
}
The preceding code displays the name of the current View in the page title and heading, and adds the user control instance created by the PageControllerBase class to the
Controls collection of an ASP.NET Placeholder control declared in the ASPX file:
The final section of the
PageLoadEvent method shown above displays the actual page URL so that you can see the effects of the Front Controller implementation (described in the next article in this series).
Figure 7 shows the two pages described in this section displaying the "CityList" View.
Author's Note: You can open the page TransferPage2.aspx with the appropriate View displayed by selecting the View name ("CustomerList," "CustomerDetails," or "CityList") in the dropdown list at the bottom of the Default.aspx page. To open the TransferPage3.aspx page with the appropriate View displayed, select "SpecialCustomerList," "SpecialCustomerDetails," or "SpecialCityList." To open the pages with no View displayed, select the page name ("TransferPage2.aspx" or "TransferPage3.aspx") in the dropdown list. |