Skip navigation

Back Draft

 

Lines of Communication

 

By Jonathan Goodyear

 

It goes without saying that lines of communication are important in almost any system in life. Programmatic systems are no different. However, communications must follow certain standards and protocols in order to be effective. Improper communications can be as bad as no communications at all.

 

You ve probably seen the canonical layer cake diagram of a properly designed application or framework. At the bottom of the cake are core components and services. Each subsequent layer consumes the services of the layer below it, sometimes adding layers of abstraction along the way. In the case of a business application, the bottom layer of the cake would be your database and stored procedures, followed by the data access/ORM layer, business logic layer, and user interface layer.

 

Communication between the layers follows very strict rules. Commands should only flow downward from upper layers to lower layers. If you think about it, it makes perfect sense. You wouldn t want your data access layer telling your user interface what to do. Likewise, .NET Framework objects don t tell your applications that consume them what to do.

 

Obviously, this doesn t mean that lower layers never pass information to higher layers. They can do it in one of two ways. First, they can send information back through method return values or output parameters when higher layers call their methods. Second, if a lower layer has something important to report that hasn t been specifically requested by a higher layer, it can raise an event containing the information. If any object in a higher layer is interested in the event, it will have subscribed to it and will receive the notification.

 

There are situations where you may not even realize that you are breaking the communication rules above. MasterPages in ASP.NET are one example. The title of one of the presentations I give at .NET user groups and Code Camps is, I didn t know you could do that with MasterPages (http://www.aspsoft.com/downloads.aspx). A question I get asked all the time is, How does my MasterPage manipulate controls on my content page? The quick answer is that it shouldn t. Of course, it is possible. Each MasterPage has a reference to the content page that is currently using it through its Page property, so you can use syntax like this in order to get a reference to a control on that page:

 

Dim lbl As Label = _

 CType(Page.Controls(0).Controls(3).Controls(1) _

 .FindControl("lblMessage"), Label)

lblMessage.Text = "Operation completed."

 

In case you re curious, you have to index into the MasterPage itself, then the HtmlForm followed by the ContentPlaceHolder, just to get to a simple Label control on the page. Aside from being a really ugly code snippet (although you can make it more elegant by using a recursion function), it is also a very brittle solution, because there is no guarantee that every content page that implements this MasterPage will have a control named lblMessage on it. Even if you check for the presence of lblMessage first, it forces your MasterPage to know far too much about the content pages that consume it. It shouldn t need to know (or determine) any of this.

 

A better solution is to follow the layering guidelines and use events to pass information between a MasterPage and content pages that consume it. Setting it up is quite simple. First, define an event in your MasterPage class:

 

Public Event Foo(ByVal fea as FooEventArgs)

 

Your event isn t required to pass any information, but it makes your event more useful if you do. You can see above that my Foo event is going to pass its information in a FooEventArgs class, which I must now define. You can define this class in many different places, but since it pertains to an event that is fired by a Web object (e.g., your MasterPage), a good place to put it is in a file named FooEventArgs.vb in the App_Code folder of your Web application:

 

Public Class FooEventArgs

 Inherits EventArgs

 Private _message As String

 Public Property Message() As String

   Get

     Return _message

   End Get

   Set(ByVal value as String)

     _message = value

   End Set

 End Property

 Public Sub New(ByVal message As String)

   _message = message

 End Sub

End Class

 

The constructor for the FooEventArgs class accepts a single string parameter that it assigns to the _message field for later retrieval by the event handler of the content page that subscribes to the event. Now, I can create a content page that consumes this MasterPage. Besides defining what MasterPage I am using in the MasterPageFile attribute of the @Page directive, I must also now add the @MasterType directive:

 

<%@ MasterType

     VirtualPath="~/MasterPageWithEvent.master" %>

 

The VirtualPath attribute is a quick way to create a strongly typed MasterPage for your content page (accessible via its Master property). Alternatively, I could have used the TypeName attribute, if I was using explicit namespaces in my code. Now that I have a strongly typed reference to my MasterPage, I can wire up an event handler to its Foo event using the following code in the content page s code-beside file:

 

Protected Sub Page_Load(ByVal sender As Object, _

     ByVal e As System.EventArgs) _

 Handles Me.Load

 AddHandler Master.Foo, AddressOf TheEventFired

End Sub

Protected Sub TheEventFired(ByVal fea As FooEventArgs)

 lblMessage.Text = fea.Message

End Sub

 

The Page_Load event wires up the Foo event of the MasterPage to the TheEventFired event handler, which extracts the Message property of the FooEventArgs object that is passed into the event and assigns it to the lblMessage Label control that is on the content page. How did the event get fired, though? That question is answered by looking at the Page_Load event of the MasterPage:

 

Protected Sub Page_Load(ByVal sender As Object, _

     ByVal e As System.EventArgs) _

 Handles Me.Load

 RaiseEvent Foo(New FooEventArgs("Hey there!")

End Sub

 

The Page_Load event of the MasterPage raises the Foo event, passing in a new instance of the FooEventArgs class containing whatever message that the MasterPage would like to convey to the content page. It is important to note that when both a MasterPage and a content page implement the Page_Load event, the content page s Page_Load event will fire first. That is why the content page is able to subscribe to the Foo event before the MasterPage raises the Foo event.

 

When working with events there is a certain amount of disconnect involved because while one object may fire many events, there is no guarantee that any other objects are listening. Objects that are in layers higher in the cake can stay as informed or uniformed as they choose. In this regard, events should not be used to broker absolutely essential messages, because the intended recipient may not be listening. Layers lower in the cake should not be permitted to enforce their will on those that sit in upper layers, though.

 

MasterPages are a unique situation in .NET, because while they are not contained in a separate physical layer as the content pages that consume them, they are arranged that way logically. Therefore, it makes sense to follow the same rules for establishing lines of communication between them. This will ensure that your Web applications are robust and can easily be decoupled without breaking things.

 

Jonathan Goodyear is president of ASPSOFT (http://www.aspsoft.com), an Internet consulting firm based in Orlando, FL. Jonathan is Microsoft Regional Director for Florida, an ASP.NET MVP, a Microsoft Certified Solution Developer (MCSD), and co-author of ASP.NET 2.0 MVP Hacks (Wrox). Jonathan also is a contributing editor for asp.netPRO. E-mail him at mailto:[email protected] or through his angryCoder eZine at http://www.angryCoder.com.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish