01 Oktober 2011

Using a Custom Base Class for your ASP.NET Pages' Code-Behind Classes

Using a Custom Base Class for your ASP.NET Pages' Code-Behind Classes

By Scott Mitchell


Introduction


One of the many benefits of object-oriented programming is that it allows for reuse of logic. For example, classes can be created that contain a base level of functionality. These base classes can then be extended through inheritance to create new classes that encompass the functionality of the base class along with any custom logic needed. The end result is that as a developer, once the base class has been created, you can extend and enhance the functionality of the base class with minimal effort. (For a more in-depth look at inheritance be sure to read Ian Stalling's article, Using Object-Orientation in ASP.NET: Inheritance.) Since the .NET Framework is built upon the principles of object-oriented programming (OOP), it's no surprise that ASP.NET borrows heavily from the tenets of OOP, one such tenet being inheritance. The base functionality for all ASP.NET pages is spelled out by the Page class in the System.Web.UI namespace. This class defines the essential properties, methods, and events for an ASP.NET page, including such members as:
  • The intrinsic objects - Response, Request, Session, and so on,
  • Common properties - IsPostBack, IsValid, and others,
  • Methods used throughout the page lifecycle, such as SavePageViewState(), ProcessRequest(), RaiseChangedEvents(), and others.
While all ASP.NET pages must be derived from the Page class, they need not be directly derived. That is, an ASP.NET page may extend a class that, itself, extends the Page class. In fact, when using the code-behind model for creating ASP.NET pages the actual ASP.NET page is derived from the code-behind class, with the code-behind class being derived from the Page class. In fact, oftentimes it makes sense to create a base class for a particular ASP.NET Web application that extends the Page class and have all code-behind classes derive from this class, rather than directly from the Page class. This universal base class can contain its own properties, methods, or events that are common to all pages in the particular ASP.NET application, or it can extend the functionality of existing methods or properties. In this article we'll look at how to create and start using a custom base class. Read on to learn more!


The Type Graph of ASP.NET Pages


ASP.NET pages have two core pieces: a markup section, which contains HTML markup and Web control syntax, and a source code portion. When using the code-behind model these two pieces are physically separated into two separate files. Alternatively, you can define the two pieces in the same file by using a server-side <script> block. When creating a page using the code-behind model the code-behind class for the page must extend, either directly or indirectly, the Page class. For example, the following shows the default code-behind class created in Visual Studio .NET when building a new ASP.NET page.
' -- VB.NET
Public Class WebForm1
    Inherits System.Web.UI.Page

#Region " Web Form Designer Generated Code "
    ... code removed for brevity ...
#End Region

    Private Sub Page_Load(ByVal sender As System.Object, _
             ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
    End Sub

End Class


// -- C#
public class WebForm1 : System.Web.UI.Page
{
	private void Page_Load(object sender, System.EventArgs e)
	{
		// Put user code to initialize the page here
	}

	#region Web Form Designer generated code
    ... code removed for brevity ...
	#endregion
}

Regardless of whether the code-behind model or inline script model is used, when the .aspx page is visited, the ASP.NET engine translates the markup section into a class and then compiles that class. If the code-behind model is being used, then the auto-generated class is derived from the page's corresponding code-behind class. On the other hand, if the inline script model is being used then the auto-generated class is derived directly from the Page class. The following diagram illustrates the resulting type graph used by both models.
Regardless of what model is being used, this auto-generated class's responsibility is to create the page's control hierarchy and render the page's markup. This is possible because the auto-generated class has the essential "guts" required to process an ASP.NET page as it is derived, either directly or indirectly, from the Page class. Furthermore, the custom page-level logic - such as your code in the Page_Load event handler, a Button's Click event handler, and so on - is present as well, either in the auto-generated class's base class (if the code-behind model is being used) or was injected directly into the auto-generated class (if the inline script block model is being used).
The point of this article, though, is not to be a thorough discussion of the page lifecycle. Rather, its intent is to focus on how to use a base class in an ASP.NET application to provide addition base logic for all ASP.NET pages. If you are interested in learning more about the page's lifecycle be sure to read Dino Esposito's article The ASP.NET Page Object Model or Solomon Shaffer's The ASP.NET Page Life Cycle.

The Basics of a Base Class


As the type graph examined above shows, the auto-generated ASP.NET page class must extend the Page class, but can do so indirectly, through a code-behind class, for example. But there's no reason why there can only be one level of encapsulation between the auto-generated class and the essential Page class. You can optionally create a base class from which all pages will derive from. When creating a base class, you'll typically have this base class extend the Page class. If you are using the code-behind model your code-behind classes will need to be modified to inherit from the new base class as opposed to the Page class. If you are using the inline script block model, you'll need to use the @Page directive's Inherits keyword to specify the type name of the class you want the auto-generated class to extend. With a custom base class the type graph for an ASP.NET page morphs into the one shown below:
As you can see in the type graph, the base class must derive from the Page class. ASP.NET page's that want to utilize the functionality of the base class will derive from this base class rather than from the Page class directly.
When creating a base class you might decide to add additional properties or methods, which are as simple as adding the appropriate properties and methods to the base class itself. Additionally, you'll likely need to extend the functionality of the Page class, adding logic at particular points in the page's lifecycle, such as common code that should run in response to the Page's Load event. To accomplish this, you'll want to override the appropriate method: OnInit to respond to the Init event; OnLoad to respond to the Load event; and OnPreRender to respond to the PreRender event.
For example, if you needed the base class to perform some logic in the Load event your base class's code would look something like:

' -- VB.NET
Public Class MyBaseClass
    Inherits System.Web.UI.Page

    Protected Overrides Sub OnLoad(ByVal e As EventArgs)
       '... add custom logic here ...
       
       'Be sure to call the base class's OnLoad method!
       MyBase.OnLoad(e)
    End Sub
End Class


// -- C#
public class MyBaseClass : System.Web.UI.Page
{
    protected override void OnLoad(EventArgs e)
    {
       // ... add custom logic here ...
       
       // Be sure to call the base class's OnLoad method!
       base.OnLoad(e);
    }
}

To have an ASP.NET page utilize the MyBaseClass base class you'd need to modify the code-behind class's syntax to extend the custom base class rather than Page:

' -- VB.NET
Public Class WebForm1
    MyBaseClass

    ...
    
    Private Sub Page_Load(ByVal sender As System.Object, _
             ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
    End Sub

End Class


// -- C#
public class WebForm1 : MyBaseClass
{
	private void Page_Load(object sender, System.EventArgs e)
	{
		// Put user code to initialize the page here
	}

    ...
}

If you are using Visual Studio .NET, the base class can be added to your ASP.NET project in one of two ways. The simplest option is to add a Class File to your ASP.NET project. To do this, right-click on the folder you want to add your project in the VS.NET Solution Explorer and choose to Add and then Add Class.
A better approach, in my opinion, is to add a new Class Library project to the Solution. To do this, right-click on the Solution in the Solution Explorer, select Add and choose New Project. Add a New Project of type Class Library in your language of choice. You can then add your base class to this new project. Finally, be sure to add a Reference from the Web application to the Class Library project by right-clicking on the Web application's References folder, selecting Add Reference. From the Add References dialog box, select the Projects tab and then add the Class Library project you just created.

Why Use a Base Class?


If you've been astutely reading along by this point you should have an understanding of the inheritance hierarchy of an ASP.NET page and know that it's possible to inject a custom base class into the hierarchy. The next natural question, though, is why would you want to do this? If you've never used a base class in this manner before, doing so sounds like a bit of extra work, so why bother? A base class is advantageous if there is some common functionality needed to be required on every ASP.NET page in your Web application. That is, if you find yourself repeatedly copying and pasting the same snippet of code into most, if not all, ASP.NET pages in your application, you should seriously consider using a base class. With a base class you can define this common behavior in one spot. The ASP.NET page's that inherit from this base class, then, will automatically perform the needed functionality. If there needs to be a change to this common logic, you'll only need to change it in one place - the base class - as opposed to having to change the code in all the ASP.NET pages.
In one of the projects I'm working on I found myself adding the code discussed in Maintaining Scroll Position on Postback to numerous pages through my site. Rather than having to add this code to each page, I quickly decided to use a base class that would provide this common functionality. I added a Boolean SmartScrolling property that defaulted to True, which indicated if the scroll position should be maintained on postback. In the OnPreRender() method I added the necessary client-side script (if SmartScrolling was True).
Another example of using a base class can be seen in another article of mine, Working with Client-Side Script. In that article I examine how to create a base class that defines a number of methods for performing common client-side tasks, such as displaying popups, setting focus to an HTML element, displaying an alert, and so on. By putting such logic in a base class, any ASP.NET page in the application that derives from the base class can utilize any of the common client-side tasks by calling the appropriate method (as opposed to having to emit the necessary script directly from the ASP.NET page's code-behind class).

Useful Base Page Class Functionality
One of the challenges of getting started using a base page class is that it's not entirely clear what goes in it. A custom base page class usually contains a mix of application-specific logic and more general useful page-level functionality that is not included in the System.Web.UI.Page class. For a look at some of the more general useful features, check out my article: Four Helpful Features to Add to Your Base Page Class.


Conclusion


In this article we examined the type graph of ASP.NET pages and saw how the base functionality of ASP.NET pages could be further customized for a particular ASP.NET application through the use of a base class. It is essential that all ASP.NET pages derive, either directly or indirectly, from the Page class in the System.Web.UI namespace. However, rather than having your code-behind classes derive from Page, in many scenarios it makes sense to create your own base class that derives from Page, having the code-behind classes derive from the base class. With this approach, any logic common to all pages can be placed within the base class.

Tidak ada komentar:

Posting Komentar