Promote Code Sharing in ASP.NET Through Inheritance and Containment
By fred _
Published: 11/12/2002
Reader Level: Intermediate
Rated: 4.00 by 1 member(s).
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Code sharing is in the mind of most programmers. The benefit of code sharing is obvious: not only is duplicated code avoided, but more importantly, maintainability is increased. Code sharing can be implemented in various ways, subject to the constraints of programming language and framework. Under object-oriented programming (OOP) model, one of the most common ways to achieve code sharing is inheritance (a.k.a. subclassing). Unfortunately, inheritance is not available to ASP web developers in the past because of the limitation of ASP parser. ASP programmers may circumvent the deficiency and achieve the goal of code sharing, to some extent, via Server-Side Include (SSI):

<!-- #Include File="Header.inc" -->

Apparently SSI is more analogous to containment (a.k.a. layering, composition, or embedding) than inheritance. Other advantages of inheritance such as member overriding and access control cannot be easily achieved by SSI.

ASP.NET, the successor of ASP, has enabled programmers to take advantage of the OOP model. The model is supported in ASP.NET by two new OOP languages: C# and VB, along with page level declarations, in particular the Inherits and Codebehind attributes. In ASP.NET, every web form (with .aspx as extension) is derived directly or indirectly from .Net Framework class System.Web.UI.Page. The class hierarchy is:

System.Object
   System.Web.UI.Control
      System.Web.UI.TemplateControl
         System.Web.UI.Page

If you use Visual Studio.NET to create a new WebForm, say WebForm1.aspx, VS.net automatically creates a code behind class named WebForm1.aspx.[cs|vb] inherited by the .aspx web page. The code behind class, in turn, inherits directly from System.Web.UI.Page . If you create another web form, say WebFrom2.aspx, then WebForm2.aspx will be inherited from the code behind class WebForm2.aspx.[cs|vb], and so on. What if WebForm1 and WebForm2 use or have something in common? For example, both pages may need the same SqlConnection, need to access resources from the same ResourceManager, or call the same user defined method.

One solution is inheritance. In the following example, I will demonstrate the use of base class to promote code sharing. The code shown in this article is in C#, but attached samples contain both VB and C#.

InheritanceSample is created as an ASP.NET web application using VS.NET. Two web forms are added: WebForm1 and WebForm2. In addition, I added a C# class MyBasePage to serve as base class for both WebForm1.aspx.cs and WebForm2.aspx.cs. MyBasePage is derived from System.Web.UI.Page. It contains one member variable, SharedString, and one member method, SharedMethod. SharedString is initialized to the FilePath of the requested web form, and SharedMethod simply returns the string "Hello World". When WebForm1.aspx is called, the result is:
Hello World from /InheritanceSample/WebForm1.aspx
Similarly, when WebForm2.aspx is called, the result is:
Hello World from /InheritanceSample/WebForm2.aspx

InheritanceSample
[MyBasePage.cs]
using System;

namespace InheritanceSample
{
	public class MyBasePage: System.Web.UI.Page
	{
		protected String SharedString;

		public MyBasePage()
		{
		// cannot define SharedString here as Request is not initialized yet.
		// SharedString = Request.FilePath;
		}

		override protected void OnInit(EventArgs e)
		{
			SharedString = Request.FilePath;
			base.OnInit(e);
		}

		protected String SharedMethod()
		{
			return "Hello World ";
		}
	}
}

[WebForm1.aspx.cs (WebForm2.aspx.cs is the same except replacing all occurrences of WebForm1 with WebForm2)]
using System;

namespace InheritanceSample
{
	public class WebForm1 : MyBasePage
	{
	}
}
						
[WebForm1.aspx (WebForm2.aspx is the same except replacing all occurrences of WebForm1 with WebForm2)]

<%@ Page Language="cs" AutoEventWireup= "false"< BR> Codebehind= "WebForm1.aspx.cs" Inherits="InheritanceSample.WebForm1"%>

<html>

            <head>

                        <title>WebForm1</title>

            </head>

            <body>

                        <%=SharedMethod()%>

                        from

                        <%=SharedString%>

            </body>

</html>


		
		

Notes:

  • The base class MyBasePage is derived from System.Web.UI.Page. No .aspx page needs to be associated with MyBasePage.
  • The codebehind classes have to be derived from MyBasePage instead of the default System.Web.UI.Page.
  • A variable whose initialization relies on object Request, Response, Application or Server cannot be initialized in the constructor of class MyBasePage. It can be initialized in the overridden method OnInit, however.
  • In order for the subclass to use the shared member, the member needs to be declared as  public, protected or protected internal.

The solution applies to any number of web forms. In APS.NET, there is a new web object type besides web form: web user control. Web user control is a user defined servlet that derives from .NET Framework class System.Web.UI.UserControl. The class hierarchy is:

System.Object
   System.Web.UI.Control
      System.Web.UI.TemplateControl
         System.Web.UI.UserControl

The attempt to share code between a web form class and a web user control class is a natural extension to the issue we addressed in InheritanceSample. But it turns out to be more challenging. The challenge arises from the fact that you cannot define a common base class for a web form and a web user control. This is because unlike C++, a C# class can be derived directly from at most one superclass. It is not possible to define a class like MyBasePage that inherits from both System.Web.UI.Page and System.Web.UI.UserControl, which are both siblings of System.Web.UI.TemplateControl. This is not a problem in C++, however, because C++ allows multiple inheritance. You may tempt to use interface to get around with C# language barrier, as C# allows a class to implement multiple interfaces. But our goal is to share implementation code, and defining implementation in an interface in not allowed.

Fortunately, containment is at our disposal. One may argue that inheritance and containment serve different purposes (is-a vs. has-a), such distinction often gets blurred. From the point of code sharing, either way may work. When we cannot resort to multiple inheritance, we don't have much choice but to ignore the subtle differences and take whichever way that works.

In the following ContainmentSample, instead of creating WebForm2 , I created a WebUserControl1 and have it included in  WebForm1 . The codebehind class of WebUserControl1 is derived from MyBaseWebUserControl. Inheritance structure for WebForm1 is the similar to the case in InheritanceSample. The difference is that I moved implementation of SharedString and method SharedMethod to class CommonClass. An object of type CommonClass is contained by both MyBaseWebUserControl and MyBasePage. SharedString and SharedMethod in both of the MyBaseXXX classes simply delegate to CommonClass. When WebForm1 is requested, the output is:

Hello World in WebUserControl1 from /ContainmentSample/WebForm1.aspx

Hello World in WebForm1 from /ContainmentSample/WebForm1.aspx

ContainmentSample

[CommonClass.cs]

using System;
using System.Web;

namespace ContainmentSample
{
	public class CommonClass
	{
		public String SharedString;

		public CommonClass(HttpRequest Request)
		{
			SharedString = Request.FilePath;
		}

		public String SharedMethod()
		{
			return "Hello World ";
		}
	}
}

[MyBasePage.cs]

using System;

namespace ContainmentSample
{
	public class MyBasePage: System.Web.UI.Page 

 

	   
	{
		protected internal String SharedString;

		CommonClass cc; // private

		override protected void OnInit(EventArgs e)
		{
			cc = new CommonClass(Request);
			SharedString = cc.SharedString;
			base.OnInit(e);
		}

		protected String SharedMethod()
		{
			return cc.SharedMethod();
		}
	}
}

[MyBaseWebUserControl.cs]

using System;

namespace ContainmentSample
{
	public abstract class MyBaseWebUserControl: System.Web.UI.UserControl 

 

	    
	{
		protected internal String SharedString;
		CommonClass cc;

		override protected void OnInit(EventArgs e)
		{
			cc = new CommonClass(Request);
			SharedString = cc.SharedString;
			base.OnInit(e);
		}

		protected String SharedMethod()
		{
			return cc.SharedMethod();
		}
	}
}

[WebUserControl1.ascx.cs (WebForm1.aspx.cs is the same as in previous InheritanceSample , except for namespace]

namespace ContainmentSample
{
	public abstract class WebUserControl1 : MyBaseWebUserControl
	{
	}
}

[WebUserControl1.ascx]

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="WebUserControl1.ascx.cs"
Inherits="ContainmentSample.WebUserControl1"%>
<%=SharedMethod ()%>
in WebUserControl1 from
<%=SharedString %>

[WebForm1.aspx]

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="ContainmentSample.WebForm1" %>
<%@ Register TagPrefix="uc1" TagName="UC" Src="WebUserControl1.ascx" %>
<HTML>
            <HEAD>
                        <title>WebForm1</title>
            </HEAD>
            <body>
                        <p>
                                    <uc1:UC id="UC" runat="server"></uc1:UC>
                        </p>
                        <p>
                                    <%=SharedMethod ()%>
                                    in WebForm1 from
                                    <%=SharedString %>
                        </p>
            </body>
</HTML>

To summarize, ASP.NET allows us to adopt an object-oriented approach to manage the complexity of web application. We examined two solutions to achieve the goal of code sharing under the constraint of C#: inheritance and containment. Because ASP.NET is backward compatible to ASP, programmers may continue using Server-Side Inclusion to promote code sharing.



Marketplace
(Sponsored Links)
What are the green links?
   



 
Copyright © 2007 CMP Tech LLC |
Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help