span.sup { vertical-align:text-top; }

Cutting Edge

The HTML Message Pattern

Dino Esposito

Code download available at:CuttingEdge2008_07.exe(514 KB)

Contents

AJAX Service Layer
General Pattern for an HTML UI
Enhanced BST Implementation
InnerHTML and DOM
HTML Message Pattern
Performance and Design Considerations
DynamicPopulate Extender
Solutions for Now

A true AJAX architecture is characterized by a neat separation between the presentation and service layers. As I discussed last month, the existence of an explicit contract between the AJAX front end and back end opens up a whole new world of programming possibilities but raises a number of architectural questions (see msdn.microsoft.com/magazine/cc546561). I covered client-side data binding and templates and discussed an implementation of the Browser-Side Templating (BST) pattern. I also briefly introduced the HTML Message (HTM) pattern as an alternative model for rendering the user interface of a Web client. This month I'll provide an enhanced implementation of BST and compare it to HTM solutions.

AJAX Service Layer

I'll refer to the server-side part of a typical AJAX presentation layer as the AJAX service layer to distinguish it from the service layer that generally represents the point of contact between the presentation and middle tier in a standard multitier architecture. Figure 1 illustrates the model.

fig01.gif

Figure 1 Typical Multitier System with an AJAX Front End

The communication between the AJAX service layer and the client front end occurs through HTTP endpoints that are exposed by Windows® Communication Foundation (WCF) services and are invoked by JavaScript proxy classes embedded in client pages. Especially when ASP.NET AJAX is the reference platform, designing and consuming services in the AJAX service layer is not a big deal. The trouble begins when you create or update the user interface.

In particular, you need powerful tools, such as JavaScript-based data binding and templates, to manipulate data on the client effectively. In this context, ASP.NET partial rendering is only a short-term solution that doesn't imply a real architectural shift. However, ASP.NET partial rendering saves you from generating the user interface programmatically. Partial rendering preserves the view state and server page lifecycle and allows you to declaratively design the user interface using controls and properties.

Such a model is still probably the best option for relatively simple Web sites, but I doubt it can be effective in an enterprise scenario where the AJAX front end is just the top tier of a deeper service-oriented system. As shown in Figure 1, the AJAX service layer represents the intermediate layer between a JavaScript front end and a set of business services. It smooths the impedance mismatch between the two tiers by adding a security barrier to protect core services in a customer-to-business (C2B) scenario and massaging data to and from JavaScript objects.

The key role played by the AJAX service layer in an AJAX architecture makes the issue of accommodating the HTML user interface based on raw data (the data returned by core services and massaged by the AJAX service layer) virtually unavoidable for architects and developers. How would you dynamically create and update a browser user interface based on raw JavaScript data?

General Pattern for an HTML UI

Years of work with ASP.NET server controls may have blurred the notion of what's really needed to build an HTML user interface. If you've had exposure to custom control development, you probably remember that it is all about accumulating HTML markup in some buffer and then outputting it to the response stream. There's no other way around this general pattern. Enhancements exist only to make it less error prone and more manageable. So the buffer where the HTML is accumulated may be a plain memory stream where you write HTML literals or a more sophisticated hierarchy of components each of which abstracts out a chunk of HTML.

In classic ASP.NET, the response of a Web page is obtained by composing a control tree that is then recursively visited. Each member of the tree receives a stream where it writes down its own HTML markup. In an AJAX model, the response of a request may be raw data serialized as JavaScript Object Notation (JSON), XML, syndication, or whatever else you like, as well as HTML generated on the server.

The BST pattern refers to a situation when a request brings raw data back to the client. The HTM pattern refers to a situation in which the request carries back ready-to-display markup.

Enhanced BST Implementation

In last month's source code, I created a JavaScript class that takes three HTML templates as input, iterates them over a collection of data, and returns the resulting HTML text. The JavaScript code in Figure 2 shows the essence of this code.

Figure 2 Get Templates

function pageLoad()
{
    if (builder === null)
    {
        builder = new Samples.MarkupBuilder();
        builder.loadHeader($get("header"));
        builder.loadFooter($get("footer"));
        builder.loadItemTemplate($get("item"));
    }
}
function getLiveQuotes()
{
    Samples.WebServices.LiveQuoteService.Update(onDataAvailable);
}
function onDataAvailable(results)
{
    var temp = builder.bind(results);
    $get("grid").innerHTML = temp;
}

HTML templates can either be defined as an HTML string or loaded from XML data islands interspersed in the page:

<xml id="item">
    <tr>
        <td align="left">#Symbol</td>
        <td align="right">#Quote</td>
        <td align="right">#Change</td>
     </tr> 
</xml>

The arbitrary syntax in the HTML template allows you to find placeholders for the data-bound items. In the sample code included here, #Quote represents the value of the property Quote in the bound data item object.

There are a few ways to improve this code and make it more useful. An essential improvement would be the ability to style items individually. So suppose that the data downloaded to the client represents the current quote and price change of a number of stocks. In this case, you might want to render in green any stocks on the rise and in red those stocks that are on a downswing. For this to happen, though, you need to inject some logic into the rendering process. Figure 3 shows an excerpt from the Samples.MarkupBuilder class used to bind a collection of stock data to a few HTML existing templates (the full code is available in this month's download).

The heart of the MarkupBuilder class is the _generate method, which is in charge of merging templates with data. In Figure 3, the _generate method takes two arguments: data and callback. In the code I presented last month, the same method takes only the data argument.

Figure 3 MarkupBuilder Class

function Samples$MarkupBuilder$_generate(data, itemCallback) 
{
    var pattern = /#\w+/g; // Finds all #word occurrences 

    var _builder = new Sys.StringBuilder(this._header);

    for(i=0; i<data.length; i++)
    {
        var dataItem = data[i];
        var template = this._itemTemplate;

        var matches = template.match(pattern); 
        for (j=0; j<matches.length; j++)
        {
            var text = matches[j];
            var memberName = text.slice(1);

            //Invoke a callback to further modify data to be bound
            var memberData = dataItem[memberName];
            var temp = memberData;
            if (itemCallback !== undefined)
            {
                temp = itemCallback(memberName, dataItem);
            }
            template = template.replace(matches[j], temp); 
          }

          _builder.append(template);
    }

    _builder.append(this._footer);

    // Return the markup
    var markup = _builder.toString();
    return markup;
}

As a client developer, you also specify a JavaScript function that the builder class will call back while processing the template for a given item. The callback function is expected to have the following prototype:

function applyFormatting(memberName, dataItem)

The first argument is the name of the placeholder without the initial # symbol. In most cases, this first argument matches the name of a public property on the bound object. The second argument is the entire data item object being bound to the current instance of the template.

The availability of the entire data object makes it possible for you to fully check runtime conditions to determine variations on the markup. Designed in this way, the callback function is logically equivalent to the server-side DataBound event of ASP.NET server controls. The following code snippet shows the JavaScript code required to change the color of the quote based on the rise or fall of the stock price:

function applyFormatting(memberName, dataItem)
{
    var temp = dataItem[memberName];
    if (memberName == "Change" && x.charAt(0) == "+")
    {
        return "<span style='color:green;'>" + temp + "</span>";
     }
     if (memberName == "Change" && x.charAt(0) == "-")
     {
         return "<span style='color:red;'>" + temp + "</span>";
     }
     return temp;
}

The logic in the code is applied only when the callback is invoked for the #Change placeholder. The callback just returns the raw member value if invoked for a different member. Figure 4 shows the final effect in the page.

fig04.gif

Figure 4 Customized Data Binding in the Browser

You're probably wondering how some cells in Figure 4 have a different background color. Well, I presented the aforementioned callback as a data-binding function, but in reality, the callback is invoked for each match found in the item template with the #xxx expression. This means that by inserting a #xxx placeholder in a template tag you can have the callback invoked and inject HTML code virtually anywhere. Here's an example:

<xml id="item">
   <tr>
      <td align="left">#Symbol</td>
      <td #Style1 align="right">#Quote</td>
     <td align="right">#Change</td>
   </tr> 
</xml>

The #Style1 expression is interpreted as a placeholder to process through the callback. The callback invocation is accompanied by the name of the pseudo-member (in this case, Style1) and the current data item. Based on the provided information, the callback can, say, change the background of the host tag to light yellow if the cell is used to render a stock whose price is on the rise:

function applyFormatting(memberName, dataItem)
{
    if (memberName == "Style1")
    {
        if (dataItem["Change"].charAt(0) == "+")
            return "style='background-color:lightyellow;'";
        else
            return "";
    }
 ...
}

In ASP.NET, most template-based controls don't apply data binding rules to header and footer regions. The Samples.MarkupBuilder component is no exception. However, there might be situations in which you want to display in the footer information that is derived from displayed data. A quick trick to do so consists of defining a scriptable element in the footer (or header) template:

<xml id="footer">
      <tr>
         <td colspan="3" align="right" 
            style="background-color:#eeeeee;">
            <small><i>provided by <b id="lblProvider"></b></i></small>
         </td>
      </tr>
   </table> 
</xml>

The content of the TD tag includes a <b> tag with a unique ID. This is sufficient to make that element further scriptable. It should be noted that the content of the XML data island is merged with raw data collected from a remote WCF service and then, when ready, inserted into the page object model via the innerHTML property of HTML browser elements.

When this happens, the browser automatically parses the contents of the HTML and updates the Document Object Model (DOM). In this way, any literal element that contains a unique ID string becomes scriptable. The following sample function is the callback associated with the call to the remote WCF service that provides stock quotes:

function onDataAvailable(results)
{
    // Bind data and update the UI
    var temp = builder.bind(results, applyFormatting);
    $get("grid").innerHTML = temp;

    $get("lblProvider").innerHTML = results[0].ProviderName;
}

Once the innerHTML property of a page element has been updated to include an element with a given ID (say, lblProvider), you can start scripting that element.

The BST pattern forces you to generate any HTML you need in the browser using JavaScript. In general, this is a good thing as it allows you to isolate all presentation logic in the one tier, as you can see in Figure 1.

In addition, by using templates and JavaScript callbacks you can keep up with the inherently dynamic nature of HTML and manage to accommodate characteristics of the data and user's expectations. Templates help you a lot in wedding code flexibility and ease of maintenance. A general-purpose class like the MarkupBuilder presented here completes the offering and closes the circle. You can't reasonably rely on JavaScript alone to generate HTML and mix generation with sprinkles of presentation logic. Code will soon get too complex, hard to read, and inevitably full of errors. Helper classes, developed with the help of the Microsoft® Client AJAX library, come to the rescue.

InnerHTML and DOM

Before I invoke the HTML Message pattern—the opposite way to generate HTML markup in an AJAX application—I want to discuss innerHTML. The DOM is a standard API through which the browser programmatically exposes the contents of the currently displayed page. The DOM represents the page as a tree of elements. Each node in the logical tree corresponds to a live object with a known behavior and its own identity.

There are three fundamental operations you can accomplish on DOM nodes: find a node, create a node, and manipulate a node. Identifying a particular node is easy as long as you know the ID of the corresponding element. The API offers a handy function:

var node = document.getElementById(id);

In ASP.NET AJAX, the getElementById function is wrapped by the $get function. If there are multiple elements with the same ID, the function returns the first that appears in the collection. To update a DOM subtree, you should remove unwanted elements and add new ones. While this approach is neat and clean from a design perspective, it can have performance problems.

Nearly all browsers also support the innerHTML property on their DOM elements. It sets or retrieves the HTML between the start and end tags of the given element. The property was introduced with the DHTML object model of Internet Explorer® 4.0 but never made its way to the official DOM API. Compared to the DOM API, though, innerHTML is much faster, especially when it comes to creating complex structures of elements. A good place to read about performance of innerHTML versus DOM is at go.microsoft.com/fwlink/?LinkId=116828. The innerHTML is not free of issues. Read about possible problems to be aware of at go.microsoft.com/fwlink/?LinkId=116827.

HTML Message Pattern

The goal of HTM pattern is having the server generate blocks of HTML markup to be displayed in the browser. A possible implementation consists of making a call to a remote URL (either a service or an HTTP handler) and receiving an HTML snippet ready for display.

The implementation of HTM relies entirely on the code you have on the server—specifically, the AJAX service layer. This is yet another good reason to favor the creation of an AJAX-specific middle layer that isolates your core services from AJAX and presentation needs and concerns (see Figure 1).

To support the HTML Message pattern, an AJAX application needs services that accomplish the task for which they have been created and can translate their calculated results to HTML snippets. Figure 5 illustrates this.

fig05.gif

Figure 5 Service that Supports HTML Message

The service composability principle is evident here. It's just a variation of the principle of reusability. In general, it applies to service-oriented architectures (SOAs) where you orchestrate business processes through composition languages like Web Services Business Process Execution Language (WS-BPEL) and get a parent service process resulting from the concatenation of a few others.

An AJAX service that outputs HTML may be seen as the composition of a core service that gets its data and a renderer service that massages it into HTML. Figure 6 shows the composed architecture of a service that returns stock quotes.

fig06.gif

Figure 6 Stock Quote Service that Supports HTML Message

In this implementation, I'm just composing classes to obtain a parent and wrapper service. From a design perspective, several classes in Figure 6 are treated as services—stock quote provider, data finder, output renderer and, as you'll see later in this column, also an input adapter.

Implementing the HTM Pattern

Figure 7 shows the contract of the stock quote service I'm using in the sample implementation of the HTM pattern. The service is built around offline and online data providers. The offline data provider returns stale values for quotes and changes, whereas the online provider connects to a real finance service and returns live data.

Figure 7 Contract of Sample StockQuote Service

namespace Samples.Services.FinanceInfo
{
    [ServiceContract(Namespace="Samples.Services",
         Name="FinanceInfoService")]
    public interface IFinanceInfoService
    {
        [OperationContract]
        StockInfo[] GetQuotes(string symbols, bool isOffline);

        [OperationContract(Name="GetQuotesOffline")]
        StockInfo[] GetQuotes(string symbols);

        [OperationContract(Name="GetQuotesFromConfig")]
        StockInfo[] GetQuotes(bool isOffline);

        [OperationContract(Name = "GetQuotesFromConfigOffline")]
        StockInfo[] GetQuotes();

        [OperationContract(Name = "GetQuotesOfflineAsHtml")]
        string GetQuotesAsHtml(string symbols, bool isOffline);

        [OperationContract(Name = "GetQuotesFromConfigAsHtml")]
        string GetQuotesAsHtml(bool isOffline);

        [OperationContract(Name = "GetQuotesFromConfigAsHtmlEx")]
        string GetQuotesAsHtml(string contextKey);
    }
}

Both providers rely on an internal finder component to actually get data. The finder component is characterized by an interface and the actual finder class is read from the configuration file. The default finder component for the offline provider uses the Microsoft .NET Framework Random class to generate just random numbers. A finder component for the online provider may use any public Web services that return financial information.

Any data that is obtained through a finder class is then composed into an HTML snippet using a renderer class. The renderer component exposes an interface and can be replaced by simply changing a setting in the configuration file. The default HTML renderer builds a table with some hardcoded styles. In this month's source code, you'll find out that the actual HTML renderer is a class derived from the default renderer that also adds a last update label. The code snippet below shows the interfaces of the finder and rendered classes:

namespace Samples.Services.FinanceInfo
  {
      public interface IFinanceInfoFinder
      {
          string ProviderName { get; }
          StockInfo[] FindQuoteInfo(string symbols);
      }
      public interface IFinanceInfoRenderer
      {
          string GenerateHtml(StockInfo[] stocks);
      }
  }

The interfaces guarantee smooth interoperability as the data obtained by the finder flows directly into the methods of the renderer.

In this implementation, the Generate­Html method of the renderer builds a table based on some predefined settings. In general, it can use any other style information that may be passed around from the client. However, the stock quote service is designed to pick up any renderer "service" that is configured on the server as the official HTML generator. All that this "service" has to do is implement the previous IFinance­InfoRenderer interface.

A sample using the markup generated via the stock service will look like this:

function getLiveQuotes()
{
    var isOffline = $get("chkOffline").checked;
    Samples.Services.FinanceInfoService.GetQuotesFromConfigAsHtml
      (isOffline,
      onDataAvailable);
}
function onDataAvailable(results)
{
    // Update the UI
    $get("grid").innerHTML = results;
}

The getLiveQuotes function is attached to a client-side event such as a button click or perhaps to a timer callback. Figure 8 shows a sample page in action. The HTML markup travels back to the client using a JSON package.

fig08.gif

Figure 8 Executing an HTML Message Pattern

Performance and Design Considerations

The HTML Message pattern moves UI generation to the server and, in particular, to the service you call from the client. This model has pros and cons. On one hand, it allows you to use managed code to implement any complex logic required to generate the markup. On the server, you can read configuration files, connect to remote services, and access databases of HTML templates with programming power that is just impossible to obtain in the browser.

At the same time, you write the code that generates the markup without much help from visual tools such as designers. Any required changes to the markup have to be addressed with C# code and there's no clear separation between layout, data, and codebehind.

A possible workaround can be found in the definition of some internal ASP.NET pages that the service queries for markup in a server-to-server scenario. These pages would work as templates; they can be created with Visual Studio® 2008 and deployed in the same IIS application that hosts the AJAX service layer. These pages will be invoked programmatically and the markup they return will be forwarded to the client.

The HTML Message pattern tends to generate more traffic than plain calls going to a service that returns raw data. It should be noted, though, that the HTML Message pattern results in less traffic than partial rendering. The more you add styles and HTML enhancements, the larger the size of the packet you return grows.

In light of this, you can decouple HTML styling from HTML layout and embed in the markup only references to client-side CSS classes for styling. If you reduce the HTML markup to just layout and data, the percentage of the extra stuff that is transferred beyond raw data may be significantly lower. During my experiments, I noted that a page built with HTML Message may sometimes result in even lower traffic than a page built with BST if you only need to display a few fields and you limit yourself to referencing CSS client classes for styling.

DynamicPopulate Extender

To wrap up, I'd like to spend some time on one of the extenders available in the AJAX Control Toolkit—the DynamicPopulate extender that goes well with an HTML Message service.

When bound to a client trigger control (say, a button), the extender invokes a service method and attaches the results to the innerHTML property of a DOM element. Needless to say, the DynamicPopulate extender requires an HTML Message service in the AJAX service layer:

<act:DynamicPopulateExtender runat="server" 
    ID="DynamicPopulateExtender1" 
    BehaviorID="DynamicPopulateExtender1" 
    ClearContentsDuringUpdate="false"
    TargetControlID="grid" 
    UpdatingCssClass="updating" 
    ServicePath="LiveQuotes.svc"
    ServiceMethod="GetQuotesFromConfigAsHtmlEx"
/>

The DynamicPopulate extender also imposes another requirement on the service that is highlighted by the input adapter service in Figure 6. The method referenced through the ServiceMethod attribute is required to have the following prototype:

string MethodName(string contextKey);

The contextKey parameter can contain any data serialized in any format that the service method knows how to process. In an input adapter service class, you take the input string and transform it into more specific parameters that other classes in the service know how to process.

One of the issues you may run into when using the extender is that it doesn't prevent the default event when the user clicks a button. So if the button is an ASP.NET button, the postback still occurs, which invalidates the service call. Here's a more common way of using the DynamicPopulate extender:

<asp:Button runat="server" id="btnRefresh" text="Live Quotes" 
    onclientclick="invoke();return false;" />

The attached JavaScript simple functions does the following:

function invoke()
{
    var extender = $find("DynamicPopulateExtender1"); 
    var isOffline = $get("chkOffline").checked;
    extender.populate(isOffline.toString()); 
}

Based on this code, the UI is updated by merging the HTML response with the element specified through the TargetControlID property of the extender.

Solutions for Now

HTML is used for presentation whereas XML, JSON, and RSS are formats that move server-generated data to the client where it can be manipulated for presentation. In the context of AJAX, this neat model is hindered by the use of the JavaScript language. Once you have downloaded data to the client, you only have JavaScript to build the UI. The BST pattern in the form of custom data binding and template techniques helps you create the UI you need.

What if you have a server-centric mindset and just hate JavaScript? What if the UI is particularly complex and you prefer to use more reliable and powerful development and debugging tools? What if both on the server and the client you end up duplicating the same heavyweight algorithm on some large data structure? Wouldn't an HTML response eliminate some concerns on the client?

In general, I believe that until we get a powerful set of controls with a rich client-side object model, we may not always employ the otherwise desirable model in which HTML is used for presentation and JSON is used for data. Today, this model may not be applicable in all situations as far as an AJAX presentation is concerned. That's why the HTML Message pattern is worth a look. It may not serve all purposes, but it has its place.

Send your questions and comments for Dino to cutting@microsoft.com.

Dino Esposito is the author of Programming ASP.NET 3.5 Core References. Based in Italy, Dino is a frequent speaker at industry events worldwide. You can join his blog at weblogs.asp.net/despos.