Object-oriented ASP.NET Programming

Applying Object-oriented Principles to Web Development with ASP.NET

Markus Egger

October 30, 2009

20 Min Read
ITPro Today logo in a gray background | ITPro Today

asp:feature

LANGUAGES: VB | C#

TECHNOLOGIES: Object-oriented Programming | Inheritance

 

Object-orientedASP.NET Programming

ApplyingObject-oriented Principles to Web Development with ASP.NET

 

By MarkusEgger

 

Webdevelopment traditionally has been somewhat unstructured. Most development hasbeen done in a very spaghetti-code-like fashion. To make matters worse, codehad to be mixed in with HTML. It was procedural at best. Server-side includeswere the state of the art for reusability. A few very bright people managed tocreate very sophisticated Web applications this way. But, overall, it was avery difficult and expensive way to program the Web. With ASP.NET, Microsoftintroduces the well-proven object-oriented methodology to Web development.Advantages seem obvious, but you have to take a much closer look to understandthe real power of this concept.

 

To trulyunderstand the power of object-oriented development, you need to revisitconventional ASP-style Web development without objects. Consider a simple buttonthat sets the value of a text box on a Web page. This seemingly simplerequirement isn t really so trivial on a Web page. First of all, you have tocreate the appropriate HTML that creates those two controls:

 

 

Thiswill render the appropriate HTML output, but it isn t functional. You need toadd some additional infrastructure, such as a tag, so the HTML page knows what to do wheneversomeone clicks the button. And there aren t many options at this point. Eitheryou can write a client-side script (which isn t the subject of this article),or you can post the current information to a page of your choice. This wouldcommunicate the two form variables (both the text box and the button arereally only variables) back to the server. There, you can have server-side codeto interpret what came along (which isn t all that trivial, either) and createa new HTML string that represents the appropriate output. Here s the completecode for the first page:

 

   

   

 

Naturally(well, naturally for Web developers, but very weird for other developers), thebutton s code (the logic that belongs to the button that was clicked) sits inthat new page. As you ll see, that s a problem.

 

Again,this seemingly simple scenario isn t so trivial in the real world, where mostserious applications have many buttons and many paths of action. The number ofpossible new output scenarios grows exponentially, and, therefore, most Webpages have very few paths for the user to take. Imagine an online shoppingcart, for instance. Once a user has finished shopping and is ready to checkout, the site usually asks him or her for a billing address, a deliveryaddress, a credit-card number, and so forth. Very often, this information isretrieved in multiple steps. Sometimes, the Web store already knows about theshopper but still displays the information for verification. Whether that makesbusiness sense or not is debatable. The reality is that even if the store knowscertain information, it s simpler to re-display it to the user than to skip itbecause re-displaying it keeps the number of paths through the scenario at aminimum. In Web applications, it s very difficult to build complex wizards thathave a large number of steps and that may skip many of them, or may show themin a different order depending on information entered at previous steps.

 

One ofthe reasons for these scenarios to be so complicated is the poorly located codethat goes with the object that causes actions. Basically, it means you have onespecific page to which you navigate as the next step, or you have multiplepages to which to navigate, but each of them needs to have the code for thebutton.

 

Neitherway is very attractive. In the first solution, your single page to which tonavigate would need to take into account all the possibilities that may occurnext. If you had a wizard that had 20 possible steps, each page would need toimplement all those options. And, if one of those steps changed, you d have tochange it in all the pages. And it gets worse: What if you wanted to add a fewpages? Ouch!

 

Thesecond option is to navigate to different next steps, which would make it mucheasier to build a flexible 20-step wizard. However, because you wouldn t besure where to navigate to, each step would have to have logic to handlewhatever happened in the previous step.

 

So yousee, it s a tossup. Either you have the duplicate effort (or 20-fold effort)for the interface, or you have the same effort for the code that goes alongwith it.

 

Objects to the Rescue

Asolution to this dilemma is to put the code where it belongs: with the button.In that scenario, whenever someone clicks the button, the code that s attachedto the button fires, and then you can decide where to navigate to. This conceptis known as encapsulation. It s one of the key concepts for all object-orientedand object-based systems, such as Visual Studio .NET and Visual Basic 6,respectively.

 

From aprogrammer s point of view, there are various ways to link click code to abutton. The easiest is event delegation, in which case you add a standardbutton to a Web Form using the appropriate ASP.NET tags in an aspx file:

 

 

Thiscreates a new button on the page. However, this time, you are not just dealingwith strings. Under the hood is code that represents this button. If you useVisual Studio .NET (and for this article, I assume you are), you can look atthe source code by right-clicking on the page and selecting View Code. There, you ll see a page object that contains a button object(this is a Visual Basic .NET example):

 

Public Class WebForm1

    Inherits System.Web.UI.Page

    Protected WithEvents Button1 As _

     System.Web.UI.WebControls.Button

End Class

 

Note that I stripped out some code that wasn t significant forthis particular example.

 

As Imentioned before, this button is more than just an HTML string that representsthe button. It is an object with properties, fields, methods, and events. Allthese things combine to make up the button. In object-terms, all those thingsare encapsulated in the button. Most of them you can access from the outside asmembers of the button, but some of them might be private and can be used onlyby the button itself. As a whole, each button object is self-contained anddoesn t require any code in any other places to function. However, standardbuttons aren t very useful by themselves because they don t do anything whenthey are clicked and don t have a useful caption. You can customize thesethings by setting properties and writing event code. To write code for theclick event, simply double-click the button from Design view, and VS .NET willtake you into source-edit mode, where it created a new click method that iswaiting for you to add more code.

 

What snot so obvious is that VS .NET just created some code that points the button tothat new click code, by delegating its event. Depending on the language youuse, the syntax will be different. In VB .NET, part of the code is defined withthe object declaration (note the WithEventskeyword above), and part of it is attached to the method definition (note the Handles clause):

 

Private Sub Button1_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) HandlesButton1.Click

End Sub

 

In C#,the general idea is fairly similar, although the syntax is a bit different.First of all, you need an event method:

 

private voidOurButton1_Click(object sender,

 System.EventArgs e)

{

}

 

Then,the event has to be delegated to that method. This happens in the InitializeComponent method:

 

this.OurButton1.Click+= new System.EventHandler(

 this.OurButton1_Click);

 

Now, youcan use the created event method to add any VB or C# code you like. Note thatat this point, the click code technically doesn t belong to the button anymore,which becomes painfully obvious when you try to copy the button into anotherform. But at least the code is in the same source file. I ll introduce a moreperfect scenario later.

 

When yourun this code, ASP.NET displays the Web page, and you can click on the button.Because you are in the same browser-based environment you have been in beforeASP.NET, all you can do at this point is navigate to some page. However, as thedeveloper, you don t worry about that at this point. That s because ASP.NETsimply navigates to the same page again, and its internal engine realizes thatall you want to do is fire the click code and so it fires it. The whole processbecomes entirely transparent for you.

 

When theclick event fires, you can make a decision about what s to happen next. Perhapsyou really want to navigate to a different page (perhaps the button is the Next button of a complex wizard), or you can simply change somethingon the current page. In the following VB .NET example, you re changing thecaption of the button itself:

 

Private Sub Button1_Click(ByVal sender As System.Object, _

 ByVal e As System.EventArgs) HandlesButton1.Click

      Button1.Text = "Hello World!"

End Sub

 

Thisshows another benefit of encapsulation: You don t have to worry about thestring that represents the button in the HTML code anymore. You simply set aproperty. The button takes care of rendering itself, so it makes sense to thebrowser.

 

Pessimistsmay say you really didn t accomplish anything you couldn t have accomplishedbefore and that all you did was change the caption of a button. And that strue. Object-oriented development doesn t enable you to do anything youcouldn t have done without it, but it makes things much easier. That s whyobject-oriented programming has been such a success. The question is notwhether it is possible to develop advanced applications without objects, butwhether such development is feasible.

 

What about Inheritance?

One ofthe greatest new features of ASP.NET is inheritance. It allows you to abstractobjects into classes and build them with entirely new behavior without startingfrom scratch. In the last example, you built a perfectly functional button.However, it wasn t very reusable. As I pointed out, the code that goes with theclick event is delegated to an external function. This means that if you wantto reuse the button on another page, you need to write the code all over again.Although you have used encapsulation successfully to get away from thelogically disconnected and somewhat chaotic scenario I outlined at the verybeginning of the article, you haven t solved the reusability issue. What youreally need is a new button that looks and behaves just like any other button,except that it has a different caption and also has standard click behavior. Tocreate such a button, create a new button class that derives from the standardbutton class. In FIGURE 1, I m using C#.

 

using System;

usingSystem.Web.UI;

usingSystem.Data;

usingSystem.Drawing.Design;

usingSystem.Web.UI.WebControls;

 

 

namespaceWebApplication2

{

   public class OurButton : System.Web.UI.WebControls.Button

   {

      public OurButton()

      {

         this.Text = "Test";

         this.Click += new

          System.EventHandler(this.OurClick);

      }

 

      private void OurClick(object sender,

       System.EventArgs e)

      {

         this.Text = "Hello World!";

      }

   }

}

FIGURE 1: A simple sub-classed button with your custom behavior.

 

In thiscase, the button itself has a method that takes care of the click. Also, thebutton has a changed caption. This is done in the button s constructor. Aconstructor is the method that fires immediately when an object is created. InVB .NET, the constructor is implemented as the New subroutine. FIGURE 2 shows the VB .NET version of the sameclass.

 

Imports System

ImportsSystem.Web.UI

Imports System.Data

ImportsSystem.Drawing.Design

ImportsSystem.Web.UI.WebControls

 

Public Class OurButton

    Inherits System.Web.UI.WebControls.Button

 

    Public Sub New()

        Me.Text ="Test"

    End Sub

 

    Private SubOurClick(ByVal sender As System.Object, _

        ByVal e As System.EventArgs) HandlesMyBase.Click

 

        Me.Text ="Hello World!"

    End Sub

End Class

FIGURE 2:The same button as in FIGURE 1 but coded in VB .NET.

 

Everythingelse in this button is identical to any other button because you inherit from aregular button. You can imagine inheritance like a very dynamic and flexiblecopying mechanism. It copies all the code required by regular buttons into yournew class and then adds whatever you may have created, which overrides thedefaults.

 

Allthat s left to do is add the button to another Web page (after you compile yournew class, of course). Here s the code to accomplish that:

 

 

Yourvery own button uses a separate namespace that defaults to cc1 (Custom Control 1, I assume). This namespace has to beregistered with ASP.NET. You can use the following directive at the top of theASP.NET page to do that:

 

<%@ RegisterTagPrefix="cc1" Namespace="WebApplication1"

 Assembly="WebApplication1" %>

 

WebApplication1 is the default namespace assignedto your application. Of course, you could change your namespace to anything youwant.

 

As youcan see, there is a little more work to do here to make ASP.NET recognize thenew button class you created. At this point, it would be much easier to dragand drop a standard button from the toolbox, rather than add the custom buttonmanually. However, you can make your button toolbox-enabled by adding a fewattributes to your C# code:

 

[ToolboxData("<{0}:OurBtnrunat=server>")]

 public class OurBtn :System.Web.UI.WebControls.Button

{ ... }

 

Again,the VB .NET version is very similar:

 

")> _

 Public Class OurBtn

    ...

End Class

 

Afterre-compiling the code, you can right-click your toolbox and select Customize Toolbox. In the dialog that pops up, selectthe .NET Framework tab and browse to your newly compiled file to see the newbutton class you created. Select it from the list and add it to the toolbox.Voil ! Now, you can use the custom button as easily as you could use thedefault button. In fact, there isn t much difference between the button youadded to the toolbox and the button that was there in the first place. Afterall, Microsoft derived that button from a more basic Web object (WebControl).

 

Again,some may say that s a lot of work to go through just to set the button scaption. And that s a good point. You wouldn t use inheritance for a scenariolike this. Instead, you d go with the standard button and the event delegation.And that s fine! Most event code for Web Forms objects will be handled in thestandard objects with simple event delegation. However, if you have an objectthat s more generic, inheritance makes a lot of sense.

 

Your First Real Derived Object

Forinstance, consider a drop-down list that shows information from a database. Youcould encapsulate this kind of functionality in a custom object, as the C# codein FIGURE 3 shows.

 

[ToolboxData("<{0}:ProdDDrunat=server>")]

 public class ProdDD :

   System.Web.UI.WebControls.DropDownList

{

   public ProductsDropDown()

   {

      DataSet oDS = new DataSet();

      SqlConnection oCon = new SqlConnection(

       "data source=(local);initialcatalog=Northwind;"+

       "integrated security=SSPI;"+

       "persist securityinfo=True;");

      oCon.Open();

 

      SqlDataAdapter oAd =new SqlDataAdapter(

       "SELECT ProductID, ProductNameFROM Products",oCon);

 

      oAd.Fill(oDS,"Products");

      oCon.Close();

 

      this.DataSource = oDS;

      this.DataMember = "Products";

      this.DataValueField ="ProductID";

      this.DataTextField ="ProductName";

      this.DataBind();

   }

}

FIGURE 3: The C# version of the specialized products drop-downlist.

 

As youcan imagine, the VB .NET version in FIGURE 4 is very similar.

 

")> _

Public ClassProdDD

   InheritsSystem.Web.UI.WebControls.DropDownList

 

   Public Sub New()

      Dim oDS As New DataSet()

       Dim oCon As New SqlConnection( _

       "data source=(local);initialcatalog=Northwind;" + _

       "integrated security=SSPI;" +_

       "persist securityinfo=True;")

      oCon.Open()

      Dim oAd As New SqlDataAdapter( _

       "SELECT ProductID, ProductNameFROM Products", oCon)

      oAd.Fill(oDS, "Products")

      oCon.Close()

 

      Me.DataSource = oDS

      Me.DataMember = "Products"

      Me.DataValueField ="ProductID"

      Me.DataTextField ="ProductName"

      Me.DataBind()

   End Sub

End Class

FIGURE 4:The VB .NET version of the products drop-down list.

 

In thisexample, the object queries information from the Northwind Products table inits constructor and populates itself automatically. FIGURE 5 shows thisdrop-down list in action.

 


FIGURE 5: The deriveddrop-down list used on a simple Web page.

 

Now, youcan drop this object on any Web Form you want and have an instant productsdrop-down list without writing a single line of additional code. And, if youwant to change this drop-down list later (to show only certain countries, forinstance), you can do so in one place, and it will change throughout yourapplication. Also, you can give this drop-down list to other developers on yourteam, and they can use it without having to worry about how the object works(just like you wouldn t worry about how a standard ASP.NET button works). Youcould even give this object to your colleagues before it is done, so they couldproceed with their development. So, even if you are very busy (and who isn t?),you can commit to specific parts of the system without holding up the wholeproject. Once you finish your class, it automatically will appear correctly onall forms.

 

It sfunctionality like this that makes inheritance so exciting. However, there is adownside. What if a change you made breaks the class? It potentially couldbreak the entire application at all ends at once. Therefore, you want to give alot of thought to massive changes you make to your systems. That is why it isso important to plan complex object systems in advance. In most cases, though,it is also relatively straightforward to fix problems you may have caused,because there is only one place where you need to fix them.

 

It isvery common for people to cause problems with these global-change scenarios asthey attempt their first steps with inheritance. However, these problems arenot specific to inheritance. Imagine if Microsoft had broken command buttons ina service pack for VB6. We haven t had any such problems on a large scale becausedevelopers usually can handle these scenarios as long as they are aware ofthem.

 

Whenpeople argue that inheritance is too dangerous a methodology to control, I mreminded of the debates about the first automobiles. Would you believe thatpeople argued motorized vehicles were too dangerous because they might run intocows? It seems silly today. Motorists pay a lot of attention to avoid hittingobjects, and that s just part of the game. Yes, every now and then, a cow (orworse, a person) does get run over. But, on a whole, the car is still a goodthing. And you know what? When I drove to work this morning, I didn t reallythink about not running into a cow. It s just second nature to a decent driver.However, a large number of accidents involve novice drivers, and the same istrue when it comes to object-oriented development and inheritance. You mightknock over a virtual tree or twoat first, but, ultimately, you will drive much faster with inherited objectsthan you ever could run without them, no matter how good an athlete you are.

 

Taking It to the Next Level

Theproducts drop-down list was very useful. I can imagine similar lists foranything from countries to sales regions. You simply could create differentdrop-down lists derived from the default list, as you did in the example shownearlier. But that would result in a lot of coding. You really want to reusecode so that you only have to write it once and can maintain it in only oneplace.

 

A goodsolution to this scenario is an intermediate class that isn t useful by itselfbut that provides common functionality that can be sub-classed into morespecific objects. Such a class generally is known as an abstract class (asopposed to a concrete class). FIGURE 6 shows the C# code for the abstract drop-downlist.

 

public classAbstractDropDown :

   System.Web.UI.WebControls.DropDownList

{

   protected DataSet oDS = new DataSet();

   protected string FieldList = "*";

   protected string TableName = "";

 

   public AbstractDropDown()

   {

      this.ConfigureObject();

      SqlConnection oCon = new SqlConnection(

         "data source=(local);initialcatalog=Northwind;"+

         "integratedsecurity=SSPI;"+

         "persist securityinfo=True;");

      oCon.Open();

 

      SqlDataAdapter oAd =new

         SqlDataAdapter("SELECT "+

            this.FieldList +" FROM"+

            this.TableName,oCon);

 

      oAd.Fill(oDS,this.TableName);

      oCon.Close();

 

      this.DataSource = oDS;

      this.DataMember = this.TableName;

      this.DataBind();

   }

 

    virtual public void ConfigureObject()

   {

   }

}

FIGURE 6: A more generic data drop-down list.

 

As youcan imagine, the VB .NET version in FIGURE 7 is similar in concept.

 

Public Class AbstractDropDown

   InheritsSystem.Web.UI.WebControls.DropDownList

 

   Public oDS As New DataSet()

   Public FieldList As String = "*"

   Public TableName As String = ""

 

   Public Sub New()

      Me.ConfigureObject()

      Dim oCon As New SqlConnection( _

       "data source=(local);initialcatalog=Northwind;" + _

       "integrated security=SSPI;" +_

       "persist securityinfo=True;")

      oCon.Open()

 

      Dim oAd As NewSqlDataAdapter("SELECT " + _

       Me.FieldList + " FROM " + _

       Me.TableName, oCon)

      oAd.Fill(oDS, Me.TableName)

      oCon.Close()

 

       Me.DataSource = oDS

      Me.DataMember = Me.TableName

      Me.DataBind()

   End Sub

 

   Public Overridable SubConfigureObject()

 

   End Sub

End Class

FIGURE 7:Your abstract drop-down list created in VB .NET.

 

In thisexample, you changed the code so it is more generic and uses properties tocreate the query string. The code still runs in the constructor of the object.But, before the query executes, it fires another method named ConfigureObject, which surprise does nothing. The idea here is to provide a simple way to add code insubclasses. In fact, the abstract class itself would fail if you tried to useit. However, consider the following derived class:

 

[ToolboxData("<{0}:ProdDDrunat=server>")]

public classProdDD : AbstractDropDown

{

   public override void ConfigureObject()

   {

      this.DataValueField ="ProductID";

      this.DataTextField ="ProductName";

      this.TableName = "Products";

   }

}

 

And theVB .NET version:

 

")> _

Public ClassProdDD

   Inherits AbstractDropDown

 

   Public Overrides Sub ConfigureObject()

      Me.DataValueField ="ProductID"

      Me.DataTextField ="ProductName"

      Me.TableName = "Products"

   End Sub

End Class

 

Itderives from the abstract class, which, in turn, derives from the standarddrop-down class. That s okay inheritance can go over an unlimited number oflevels. In fact, the drop-down class derives from other classes, as well.

 

When theProdDD class runs, it will do everything its parent class does, whichincludes running the constructor. In the constructor, the class calls its ConfigureObject method. Now, here iswhere the power of inheritance really kicks in. Because you overrode thatmethod in your latest class, that code will run rather than the code in theabstract class. This allows you to configure the object appropriately beforethe actual query runs.

 

Withthis basic architecture in place, you easily can create another drop-down for adifferent table; for example, Customers:

 

[ToolboxData("<{0}:CustDDrunat=server>")]

 public class CustDD : AbstractDropDown

{

   public override void ConfigureObject()

   {

      this.DataValueField ="CustomerID";

      this.DataTextField ="CompanyName";

      this.TableName = "Customers";

   }

}

 

In VB.NET, it s as follows:

 

")> _

 Public Class CustDD

   Inherits AbstractDropDown

 

   Public Overrides Sub ConfigureObject()

      Me.DataValueField ="CustomerID"

      Me.DataTextField ="CompanyName"

      Me.TableName = "Customers"

   End Sub

End Class

 

In fact,you can even take this a step further and create a special customer class thatshows the name of the contact person instead of the company name:

 

[ToolboxData("<{0}:CustDD2runat=server>")]

public classCustDD2 : CustDD

{

   public override void ConfigureObject()

   {

      base.ConfigureObject();

      this.DataTextField ="ContactName";

   }

}

 

In VB.NET, it s:

 

")> _

Public ClassCustDD2

    Inherits CustDD

 

    Public Overrides Sub ConfigureObject()

        MyBase.ConfigureObject()

        Me.DataTextField ="ContactName"

    End Sub

End Class

 

In thisexample, you override the ConfigureObjectmethod. However, you change only one property, and you want everything else tobe the way it was in the customer class. Normally, overriding a method wipesout everything that was there before. But, in this case, you would like to addyour code to the existing code. You can do so by specifically calling the codein the parent class (also known as the base class), through the base pointer inC# and the MyBase pointer in VB.NET. You can call the base functionality at any point in the method. In theexample, you do it before setting the property to make sure your new codealways has the last word.

 

As youcan see, inheritance becomes more useful in scenarios that are more complex.This is why the true power of inheritance is sometimes hard to explain.

 

Conclusion

Theaddition of object-oriented technology to ASP.NET finally has put an end tohighly complex and confusing string concatenations. Object-oriented programmingfeatures enable the developer to build reusable code and create Webapplications that can rival Windows applications in functionality. In thisarticle, I was only able to scratch the surface of object-oriented development.In future articles, I hope to dig much deeper into even more excitingpossibilities.

 

Markus Eggeris president of EPS Software Corp., located in Houston, TX. He is also thefounder of EPS Software Austria, located in Salzburg. He concentrates onconsulting in .NET and COM-based, object-oriented development and Internetapplications. He is an international author and speaker and is co-publisher of Component Developer Magazine. He is also the author of AdvancedObject-Oriented Programming with Visual FoxPro, from Hentzenwerke Publishing. For the past several years, Markushas received the Microsoft MVP award, and several applications on which he hasworked (mostly as project manager) have received Microsoft Excellence Awardnominations. For more information, visit http://www.eps-software.com/MarkusEggeror e-mail Markus at mailto:[email protected].

 

Tell us what you think! Please send any comments about thisarticle to [email protected] include the article title and author.

 

 

 

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like