Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Computing
Conference & Expo
November 2-4, 2009 NYC
Register Today and SAVE !..
SYS-CON.TV
Today's Top SOA Links


Standardizing an ASP.NET Web Site
Standardizing an ASP.NET Web Site

In large Web sites, there are generally just a couple of unique page layouts. In the past, developers had to duplicate large chunks of code on each page. Doing so made the site hard to maintain and difficult to change on a global scale. This tended to be an issue even when using include files, as it was difficult to pass page-specific information down the chain. To the rescue are the .NET Web User Controls and their ability to interact with a parent page's exposed custom properties. Through an assortment of referenced custom controls, the look and layout of a site can be enforced and page differences can be controlled from one location on the parent page. Additionally, global site changes can then be made by simply changing a single control.

In this article, I assume that you are familiar with the creation of ASP.NET WebForm pages and Web User Controls, and the use of the various other ASP.NET controls.

The Dark Ages
Before .NET, standard ASP pages tended to become a spaghetti plate of HTML and code intertwined with each other. Over time several techniques were developed for cleaning up this HTML/code interdependence as much as possible. One such technique was to use include files for anything that appeared on more than one page. An include file used the following IIS directive hidden in an HTML comment:

<!-- #INCLUDE VIRTUAL="/site/includepage.asp" -->

This method worked fine at first, but as the complexity of our sites increased, so did the issues involved with them. One such issue was that the included pages inherited the same environment as the parent page, so any variables declared would carry over, the original query string would carry over, etc.

For some things this was good. For instance, you could define a variable "color" on the parent page, then on the included page reference it with:

<%=color%>

However, you could not transfer data to the include page through any query string values as in:

<!-- #INCLUDE VIRTUAL="/site/include page.asp?color=red" -->

Additionally, if you tried to assign or redeclare a variable, such as "color", on the included page, it would stomp on the parent page's value, or raise an error condition.

With all this in mind, you can see that the old way was not very elegant, and was prone to errors. Tracking the cause of these errors was also very difficult since it was hard to trace the interdependence of these pages.

The Enlightenment
ASP.NET introduces a replacement for the old include files in its Web User Control. A Web User Control is similar to an include file in that it contains a block of HTML, but it also has a programmatic interface to encapsulate any data and also executes in an environment independent from the page that uses it.

In the simplest case, a Web User Control just contains a block of HTML code to place on a page wherever the control is referenced:

<uc1:Control1 id="control1" runat="server" />

In a more complex case, a control exposes properties that can be set by the page when the control is referenced:

<uc1:Control1 id="control1" customProperty="green"
runat="server" />

This provides a more elegant means of communicating information into the control from the parent page. Both the page and control can use a variable called "color", but the value must be passed explicitly from the parent page to the control. No more stepping on each other's toes.

180-Degree Spin
Above, I described how to pass information to a control from a parent page. This is the typical way that data communication occurs from a parent page to its child controls.

However, what if you have a site with hundreds of pages using the same controls several times per page? Every time the control appears on the page, you have to assign a value to the custom control properties. If you want to provide the same value to several controls, you will get something like this:

<uc1:Control1 id="control1" userName="Jeff" runat="server" />
<uc1:Control2 id="control2" userName="Jeff" runat="server" />
<uc1:Control3 id="control3" userName="Jeff" runat="server" />

Seeing the duplication of hard-coded values above should immediately raise a red flag. The problem is that if the userName changes, the value has to be changed in three different places. It would be much cleaner to simply be able to change it in only one place, and have every control on the page inherit the single value. Implementing that goal is what the remainder of this article is about.

There really are two ways to achieve the goal of having page controls automatically gain access to a parent page's properties. I will start with the most elegant one, which is inheritance. However, there are problems with using this technique in Visual Studio, so I will also provide an alternative method, which is through the use of an interface.

The Project
The sample code provided throughout the remainder of this article references a sample project I developed that consists of three pages, and three controls that appear on each page. Each page lays out the control locations in a table and sets properties that the controls inherit. This page layout consists of a title area populated by Control1, a menu area populated by Control2, and a content area populated by Control3 (see Figure 1). The variables defined on each page that I want the controls to access are:

private System.Drawing.Color color;
private string title;

These consist of the color scheme and the title of the page. Since the variables are private, they need to be exposed to code outside the page through the following public property blocks:

public string Title
{
set {title = value;}
get {return title;}
}

public System.Drawing.Color Color
{
set {color = value;}
get {return color;}
}

The three pages that I created are "PageRed", "PageGreen", and "PageBlue", which utilize the same three controls. The controls look different on each page, however, depending on the values of each page's custom properties. Figures 2, 3, and 4 show the changes on each page: the title text and color, the menu area color, and the name of the color in the content area.

The code defining the page properties looks simple enough at first, but our controls still cannot access these properties directly. Since a WebForm page inherits from System.Web.UI.Page, and the Page class does not implement a "Color" or "Title" property, a control will raise an exception if it tries to do something like the following:

System.Drawing.Color localColor = Page.Color;

So, how can we get the controls to see these properties? The answer is inheritance.

Base (Template) Page Class
Since the custom properties we want to access from all controls ­ "Color" and "Title" ­ are not part of the System.Web.UI.Page class, we need to subclass it and add these new properties. This simply requires creating an empty WebForm called "BasePage.aspx" with the code shown in Listing 1.

BasePage inherits from System.Web.UI.Page as usual, and implements the two new properties that we desire to have on every page. Once this is created, we have each of our pages inherit from this new class instead of the built-in Page class. Each of our page class declarations look like the following:

public class PageGreen : BasePage
{
...
}

We need to be able to set properties on a page level, then allow included controls to find and access them. All of our pages will now automatically inherit support for our two custom properties. Additionally, there is now a mechanism for our controls to expect and find these properties, which I will cover in the next section.

Since the pages automatically inherit the two properties, we can simply assign a value to them once on each page's Page_Load handler:

private void Page_Load(objectsender, System.EventArgs e)
{
// Set the page's custom properties
Color = System.Drawing.Color.FromName("Green");
Title = "A Grassy Meadow Color";
}

Controls
In order for our controls to find the two properties of our pages, they need to be able to expect them to be there. Instead of treating the control's Page property as a System.Web.UI.Page class, we need to treat it as a BasePage class. This is done through a cast; for example, to set the text and color of a title Label via the Page_Load handler of Control1, we do the following:

private void Page_Load(objectsender, System.EventArgs e)
{
// Set control properties based on parent page values
TitleLabel.Text = ((BasePage)Page).Title;
TitleLabel.ForeColor = ((BasePage)Page).Color;
}

The control gets the Page property, which is expected to be of type System.Web.UI.Page, and instead treats it like a BasePage type, which it actually is. Now the two properties are available for access.

That's all there is to it. We created a new base page class that defines all the custom public properties that a page will expose. We inherited from that page on each of our real pages, and we assigned values to the properties in its Page_Load handler. Then each control that needs a value from the page gets its Page property, casts it as our base page, and accesses the custom property values.

Issues and an Alternative
The above solution, in my opinion, is the most elegant. However, Visual Studio 7 (at least Beta 2) disagrees with me. The Beta 2 designer does not know what a "BasePage" class is and therefore cannot interact with it properly. It is not smart enough (yet?) to realize that the BasePage in turn inherits from System.Web.UI.Page so it can treat it like a Page class.

In the real world, I found that the ability to use the visual design tools outweighs the elegance of inheritance. Luckily, there is another solution almost as nice that works flawlessly ­ the implementation of a custom interface.

Instead of creating a base page to inherit from, we will define our properties through an interface and require that each page implement that interface. This allows us to cast the page in each control as the interface with the same result as using a base page class. The drawback is that we have to implement the properties on every page, rather than just on a single page that we inherit from.

So, the interface is defined through a simple .cs file as:

public interface IPageTraits
{
string Title {set; get; }
System.Drawing.Color Color {set; get; }
}

It tells all our pages that they have to implement a set and get function for the two properties we want them to expose. Each page declaration will then appear as shown in Listing 2 and will be required to implement the two properties of the interface.

Notice that our pages inherit from System.Web.UI.Page and also implement IPageTraits. C# can only inherit from one parent class, but it can implement any number of interfaces. It would be nice to have multiple inheritance in C# because we could inherit from page as well as another class that has our custom properties, but that is not an option.

Our control code then needs only to cast the page as an IPageTraits object to access our properties:

private void Page_Load(objectsender, System.EventArgs e)
{
// Set control properties based on parent page values
TitleLabel.Text = ((IPageTraits)Page).Title;
TitleLabel.ForeColor = ((IPageTraits)Page).Color;
}

Conclusion
Things have come a long way since the days of include files and hard-to-follow code. The object-oriented capabilities of ASP.NET coupled with Web Custom Controls allow a higher degree of power, customization, and encapsulation than anything prior. The result is cleaner code and a unified structure that can make maintaining a large site a breeze.

About Jeff Jorczak
Jeff Jorczak built his first computer at the age of 10 using tinker toys, string, and a dismembered Barbie doll. Since then, he has maintained a strong addiction to shuffling 1's and 0's into ever increasing patterns of complexity. Jeff has worked for the past several years as a freelance consultant focusing on the complete spectrum of Microsoft technologies, with
a few other products thrown in along the way. Prior to that, he spent a number of years creating video games in California.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers
ADS BY GOOGLE