October 2017

Volume 32 Number 10

[Web Development]

Speed Thrills: Could Managed AJAX Put Your Web Apps in the Fast Lane?

By Thomas Hansen | October 2017

According to several studies on the subject, two of the most important concerns when creating an AJAX Web app are speed and responsiveness. These are probably some of the reasons why some developers choose to create native apps instead of Web apps. But what if I told you there exists a way to create AJAX Web apps that are 100 times faster and more responsive than the apps you might know?

I've invented a way to create 100 percent pure JavaScript-based AJAX Web apps that reduce the bandwidth usage for your apps by at least 10 times, sometimes by as much as 300 times, depending on what types of tools you're using and what you want to create. I refer to this technique as "Managed AJAX."

Managed AJAX is to some extent inspired by the way Microsoft built the common language runtime (CLR). For instance, when you create a C# application, the compiler creates a CLR assembly. This implies that your runtime environment for your end result is a “managed environment.” When you create a managed AJAX app, your result doesn’t compile down to anything different than a normal plain ASP.NET Web site; it becomes a managed environment, where the JavaScript parts of your end results are completely abstracted away, the same way the CPU instructions are abstracted away when you have a CLR assembly.

How Does This Work?

Managed AJAX requires almost no new knowledge. If you've done any ASP.NET development, you can drop a new Control library into your .aspx pages, and continue your work, almost exactly as you've done before. You create a couple of ASP.NET controls, either in your .aspx markup, or in your C#/F#/Visual Basic .NET codebehind. Then you decorate your controls' properties, add a couple of AJAX event handlers and you're done!

The initial rendering creates plain-old HTML for you. But every change you make to any of your controls on the server side during an AJAX request is passed to the client as JSON. Therefore, the client can get away with a tiny JavaScript library, less than 5KB in total size, and you can create rich AJAX controls, such as TreeViews, DataGrids and TabViews, without ever having to use more than 5KB of JavaScript.

Realize that at this point, you've already outperformed jQuery as a standalone JavaScript file by almost one order of magnitude (jQuery version 2.1.3 after minification and zopflinication is 30KB). Hence, by simply including jQuery on your page, and no other JavaScript, you've already consumed 6 times as much bandwidth as you would using a managed AJAX approach. As you start consuming jQuery in your own JavaScript, this number skyrockets.

Pulling in jQuery UI in its minified and zipped version makes your JavaScript portions increase by 73.5KB. Simply including jQuery and jQuery UI on your page increases its size by an additional 103.4KB (103.4KB divided by 4.8KB becomes 21.5 times the bandwidth consumption). At this point, you still haven't created as much as a single UI element on your page, yet jQuery+jQuery UI consumes almost 22 times the space of your managed AJAX approach. And you can create almost every possible UI widget you can dream of with this 5KB of JavaScript, including most UI controls that jQuery+jQuery UI can create. Basically, regardless of what you do, you'll rarely if ever exceed this 5KB limit of JavaScript. And the other parts of your app, such as your HTML and your CSS, might also become much smaller in size.

Using this approach, you create rich AJAX UI controls, such as AJAX TreeView controls, DataGrid controls and TabView controls. And you never need additional JavaScript as you create these widgets. There's also no new knowledge required to use these controls. You simply use them (almost) the same way you'd consume a traditional WebControl from ASP.NET.

The managed AJAX approach has two distinct ways of handling the HTTP requests to your page. One of the handlers is the normal plain HTTP request, which will simply serve HTML to the client. The other handler lets you check for the existence of an HTTP post parameter. If this parameter exists, the handler will render only the changes done to each control back to the client as JSON. During an AJAX request, each control created by modifying the page's control hierarchy will be automatically recreated for you, with the properties it had in your previous request. On the client side, you have a general handler that handles your JSON properties to your controls and generically updates the attributes and DOM event handlers of the DOM elements on the client.

This approach has a lot of positive side effects, such as not fighting the way the Web was originally created by rendering the HTML elements as just that—HTML elements. That implies that semantically, your Web apps become more easily understood (by search engine spiders, as an example). In addition, it creates a superior environment for actually modifying things on the client, if you wish to use the best of both worlds.

You can still combine this approach—with as much custom JavaScript as you wish—at which point you can simply inspect the HTML rendered in your plain HTML requests. Compare this to the "magic div" approach, used by many other AJAX UI libraries, often containing megabytes of JavaScript to create your DataGrids and TreeViews.

Thus, you can understand that the 100 times faster and more responsive figure isn't an exaggeration. In fact, compared to all the most commonly used component UI toolkits, used in combination with C# and ASP.NET, it's usually between 100 and 250 times faster and more responsive with regard to bandwidth consumption. I recently did a performance measure between the managed AJAX TreeView widget in System42 and three of the largest component toolkits on the ASP.NET stack. I found the difference in bandwidth consumption to be somewhere between 150 and 220 times faster and more responsive.

To illustrate what this implies, imagine you're on an extremely slow Internet connection, where it takes one second to download 5KB of JavaScript. This implies one second to download the managed AJAX JavaScript and possibly as much as three minutes 40 seconds to download the JavaScript parts of some of the other toolkits. Needless to say, imagine what the difference would be with regard to conversion if you built two e-commerce solutions with these two approaches.

Show Me the Code

OK, enough talk, let's get down and dirty. First, download Phosphorus Five at bit.ly/2u5W0EO. Next, open the p5.sln file and build Phosphorus Five, such that you can get to your p5.ajax.dll assembly. You're going to consume p5.ajax.dll in your Web app as a reference, so you need to build it before you proceed. Notice that Phosphorus Five consists of more than 30 projects, but in this article I'm focusing on the p5.ajax project.

Next, create a new ASP.NET Web site in Visual Studio. Make sure you create a Web Forms application. In Visual Studio for Mac, you can find this under File | New Solution | Other | .NET | ASP.NET Web Forms Project.

Create a reference inside your newly created Web site to the already built p5.ajax.dll assembly and modify the web.config to resemble the following code:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <pages clientIDMode="Static">
      <controls>
        <add assembly="p5.ajax" namespace="p5.ajax.widgets" tagPrefix="p5" />
      </controls>
    </pages>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
</configuration>

The important parts in this code are the "clientIDMode" and the "add assembly." At this point you can use any of the p5.ajax controls from inside your .aspx markup by prefixing them with p5. Make sure you modify the Default.aspx page's content to resemble the code in Figure 1.

Figure 1 Creating a Page with a Single Button that Changes Its Text When Clicked

<%@ Page Language="C#" Inherits="foobar.Default" %>
<!DOCTYPE html>
<html>
<head runat="server">
  <title>Default</title>
</head>
<body>
  <form id="form1" runat="server">
    <p5:Literal 
      runat="server"
      id="foo"
      onclick="foo_onclick"
      Element="button">Click me!</p5:Literal>
  </form>
</body>
</html>

Then change its codebehind to the following:

using System;
namespace foobar
{
  public partial class Default : p5.ajax.core.AjaxPage
  {
    [p5.ajax.core.WebMethod]
    public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      sender.innerValue = "Hello World from Managed Ajax!";
    }
  }
}

Notice that you first need to inherit your page from AjaxPage, add a WebMethod attribute to the event handler and specifically strongly type the first parameter to your event handler as a "Literal" widget. At this point you can start your Web site, click the button and enjoy your result. If you get weird bugs when debugging your Web site, make sure you turn off the "browser link" settings for Visual Studio, which is normally a toolbar button, at the top of Visual Studio. If you're curious about what goes on here, try to inspect your HTTP requests. Also make sure you take a look at its initial HTML.

Whoa, What Was That?

That was managed AJAX in practice. There are several important points to this idea that should be considered. First, you can modify any property in any control on your page from any AJAX event handler in your page. If you created another Literal widget, "Element" type "p" for instance, you could update its content from your button's "foo_onclick" event handler.

Second, you can dynamically add, remove, update or retrieve any property from your widget any way you see fit. To reference any attribute or event handler, simply use the subscript operator from C#. In Figure 2, instead of setting the widget's innerValue, its style property is checked and toggles a yellow background, using the CSS style property. Notice how it's able to persist and "remember" the style property of your widget. Notice also that this is done without passing huge amounts of ViewState back and forth between the client and the server.

In a real-world application, you'd probably want to use CSS classes, which could be done by exchanging the reference in Figure 2 from "style" to "class." But I wanted to keep this example simple, so I didn't mix CSS files in here, instead using the style attribute for convenience. Using the approach shown in Figure 2, you can add, remove and change any attribute you wish, on any widget on your page.

Figure 2 Toggling the Background Color

using System;
namespace foobar
{
  public partial class Default : p5.ajax.core.AjaxPage
  {
    [p5.ajax.core.WebMethod]
    public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      if (sender.HasAttribute ("style"))
        sender.DeleteAttribute ("style");
      else
        sender ["style"] = "background-color:Yellow;";
    }
  }
}

And the third—probably most important—point is that you can dynamically add, remove, update and insert any new AJAX control into any other widget, as you see fit. Before you have a look at this final point, though, you'll need to examine the "trinity of widgets."

There are three different widgets in p5.ajax, but they're also very similar in their API. By combining these three widgets together using composition, you can create any HTML markup you wish. In the example in Figure 2, you used the Literal widget. The Literal widget has an "innerValue" property, which on the client side maps to "innerHTML," and simply lets you change its content as a piece of string or HTML.

The Container widget can contain widgets. And it will remember its Controls collection and let you dynamically add, remove or change its collection of controls dynamically during AJAX requests.

The third widget is the Void widget, which is exclusively used for controls that have no content at all, such as HTML input elements, br elements, hr elements and so on. The most important one for the example here is probably the Container widget. So go ahead and change the code in the .aspx page to what you see in Figure 3.

Figure 3 Creating a Page with a Button and a Bulleted List Containing One List Item

<%@ Page Language="C#" Inherits="foobar.Default" %>
<!DOCTYPE html>
<html>
<head runat="server">
  <title>Default</title>
</head>
<body>
  <form id="form1" runat="server">
    <p5:Literal 
      runat="server"
      id="foo"
      onclick="foo_onclick"
      Element="button">Click me!</p5:Literal>
  <p5:Container
      runat="server"
      id="bar"
      Element="ul">
      <p5:Literal
        runat="server"
        id="initial"
        onclick="initial_onclick"
        Element="li">Initial list element, try clicking me!</p5:Literal>
  </p5:Container>
  </form>
</body>
</html>

The widget hierarchy in Figure 3 will create one "button" and a "ul" element with one "li" child element. Next, change the C# code behind to the code in Figure 4.

Figure 4 Mapping Up AJAX Event Handlers to Create a New List Item

using System;

namespace foobar
{
  public partial class Default : p5.ajax.core.AjaxPage
  {
    protected p5.ajax.widgets.Container bar;

    [p5.ajax.core.WebMethod]
    public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      // Using the factory method to create a new child widget for our "ul" widget.
      var widget = bar.CreatePersistentControl<p5.ajax.widgets.Literal>();
      widget.Element = "li";
      widget.innerValue = "Try clicking me too!";

      // Notice we supply the name of the method below here.
      widget ["onclick"] = "secondary_onclick";
    }

    [p5.ajax.core.WebMethod]
    public void initial_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      sender.innerValue = "I was clicked!";
    }

    [p5.ajax.core.WebMethod]
    public void secondary_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      sender.innerValue = "I was ALSO clicked!";
    }
  }
}

Realize that the last piece of code dynamically injected new widgets into the Container widget. Basically, new "li" elements were appended into the "ul" element, dynamically during an AJAX request, and it simply worked! These widgets are also persistently remembered across AJAX requests, such that you can change their properties and invoke event handlers for them. In addition, through the "Element" property any HTML elements can be rendered and any attribute added through the subscript operator.

You now have 100 percent perfect control over your HTML markup, and you can create tiny AJAX requests and responses that update anything you want to update on your page in any way you see fit. And you did it with 4.8KB of JavaScript. You've turned Web app AJAX development into a thing that can be done just as easily as plain-old Windows Forms development. And in the process, you ended up with 100 times faster and more responsive Web apps.

An Exercise in Hyperlambda

A few months back I wrote an article in the June 2017 issue of MSDN Magazine titled “Make C# More Dynamic with Hyperlambda” (msdn.com/magazine/mt809119), which explored the non-traditional Hyperlambda programming language with its roots in execution trees. I bring this up because Hyperlambda’s tree-based approach makes it extremely easy to declare an AJAX widget hierarchy. Combine p5.ajax with Hyperlambda to consume an AJAX TreeView widget, and some impressive efficiencies show up.

Let's explore this. First, in addition to Phosphorus Five, you need to download System42 and put it into the main p5.webapp folder according to the instructions at bit.ly/2vbkNpg. Then start up System42, which contains an ultra-fast AJAX Tree View widget, open up "CMS," create a new lambda page by clicking the +, and paste the code shown in Figure 5.

Figure 5 Creating an AJAX TreeView, Which Will Allow for Traversing Folders on Disk

create-widget
  parent:content
  widgets
    sys42.widgets.tree
      crawl:true
      items
        root:/
      .on-get-items
        list-folders:x:/../*/_item-id?value
        for-each:x:/@list-folders/*?name
          list-folders:x:/@_dp?value
          split:x:/@_dp?value
            =:/
          add:x:/../*/return/*
            src:@"{0}:{1}"
              :x:/@split/0/-?name
              :x:/@_dp?value
          if:x:/@list-folders/*
            not
            add:x:/../*/return/*/items/0/-
              src
                class:tree-leaf
        return
          items

Click Settings, choose empty as your Template, click OK, save your page and click View page.

Try expanding the AJAX Tree View while inspecting what goes over the wire in your HTTP requests, and realize that you just built a folder browsing AJAX Tree View with 24 lines of Hyperlambda that will display your folders from your p5.webapp folder, and that its initial total bandwidth consumption was only 10.9KB!

If you compare these results with any other AJAX toolkit, you'll often find that other toolkits require downloading several megabytes of JavaScript—in addition to all the other stuff that goes over the wire—while Hyperlambda TreeView has no more than 4.8KB of JavaScript.

This AJAX Tree View was built with a total of 717 lines of code, in pure Hyperlambda, using nothing but the Literal, Container and Void widgets. Most of its code is made up of comments, so roughly 300 lines of code were required to create the AJAX Tree View control. The widget was consumed with 24 lines of Hyperlambda, which let you browse your folders on disk. But it would require thousands of lines of code to create the control with anything else, and hundreds of lines to consume it, as was done in the 24 lines of code in Figure 5.

If you wanted, you could now exchange three lines of code in the Hyperlambda example and end up with your own specialized Active Event custom widget, which would let you consume your specialized widget with a single line of code. Read how to do that at bit.ly/2t96gsQ.

So, you're now able to create an AJAX Tree View that will browse your server's folders with one line of code. To create something equivalent in other toolkits would often require hundreds of lines of code in four different languages. You did it with one line of code, in one programming language and it performs up to 300 times better than its competition.

Wrapping Up

Imagine being able to produce 100 times better results, 100 times faster and more optimized results, 100 times better quality, with 100 times fewer less bugs, and being 100 times more productive than you were before. To make sure you're using the latest goods, download Phosphorus Five at bit.ly/2uwNv65 and System42 at bit.ly/2vbkNpg.


Thomas Hansen has been creating software since he was 8 years old, when he started writing code using the Oric-1 computer in 1982. Occasionally, he creates code that does more good than harm. His passions include the Web, AJAX, Agile methodologies and software architecture. Contact him at thomas@gaiasoul.com.

Thanks to the following Microsoft technical expert for reviewing this article: James McCaffrey


Discuss this article in the MSDN Magazine forum