.NET Framework 4 Beta 2 has been out for a little while now. There are some subtle improvements to the ScriptManager control in ASP.NET 4.0 that few have picked up on yet. Allow me to introduce you to them! First, let me say that this is strictly about features in the server-side ASP.NET ScriptManager control, not the Ajax library in general. Also – if you do not use the ASP.NET Ajax library but you are a WebForms developer, I assume you, this article is still for you!

EnableCdn? Yes please.

This one has been blogged about by ScottGu already, but for completeness, here it is. The ASP.NET Ajax scripts are now hosted in a Microsoft CDN, and you can tell ScriptManager to load them from there by simply enabling this property. For virtually no work you get better performance, less bandwidth usage, and a cleaner rendering due to those ScriptResource.axd urls going away from your HTML. Do read the linked post for details. But wait, there’s more!

What has not really been blogged about is this: The EnableCdn property isn’t only for ASP.NET Ajax scripts. Even the scripts in System.Web.dll are on the CDN. So if you are using a GridView, TreeView, or Validators, for example – those scripts will load from the CDN, too. It wouldn’t have been the best experience if only only some scripts were affected by this setting, right?

But what if you are using custom scripts, or 3rd party controls? How would that work? Here’s how.

Normally, when you embed a script within an assembly for use by a WebForm (either via ScriptManager or the classic GetWebResourceUrl and RegisterScriptResource APIs), you have to define a WebResourceAttribute for it, which allows it to be accessed via the WebResource.axd or ScriptResource.axd handlers:

[assembly: WebResource("Foo.js", "application/x-javascript")]

Now, there’s a new property on WebResourceAttribute: CdnPath. Don’t get too caught up on the fact it’s a hard coded url. More on that later.

[assembly: WebResource("Foo.js", "application/x-javascript", CdnPath = "http://foo.com/foo/bar/foo.js")]

ScriptManager looks for this property when the EnableCdn property is set to true, and simply uses that path instead of the ScriptResource.axd path to the assembly resource. Pretty simple. And this means that you too can provide your own CDN paths for your own assembly resource scripts. As for where to host your script, well, that’s up to you.

 

AjaxFrameworkMode.Disabled

ScriptManager does some interesting and useful things, like: script combining, serving scripts from assemblies, script localization, script globalization, removing of duplicate references, automatic switching between debug and release scripts, and now automatic switching to a CDN. Trouble is, it comes with a bit of a tax: It always includes the Microsoft Ajax library (MicrosoftAjax.js), and by default, MicrosoftAjaxWebForms.js (for partial rendering support with UpdatePanel). The partial rendering script could be removed by setting EnablePartialRendering=false, but there was no way to disable MicrosoftAjax.js. So if you wanted to use the useful features of ScriptManager without using MicrosoftAjax.js, well, you couldn’t (although Bertrand once blogged a way of hacking it by making use of it’s de-duping process).

The AjaxFrameworkMode property adds two new modes to ScriptManager’s behavior. Enabled (the default, and the same behavior as before), Explicit (does not include any scripts by default but still assumes Microsoft Ajax is to be utilized), and Disabled (does not include any scripts by default and does not assume Microsoft Ajax will be used).

So here I have a ScriptManager that is including a custom script, without also loading MicrosoftAjax.js or any of the inline script it normally produces.

<asp:ScriptManager runat="server" AjaxFrameworkMode="Disabled">

    <Scripts>

        <asp:ScriptReference Path="~/scripts/foo.js" />

    </Scripts>

</asp:ScriptManager>

AjaxFrameworkMode.Explicit

The client side script for ASP.NET AJAX 3.5 (the one baked into ASP.NET 3.5) is basically just MicrosoftAjax.js and MicrosoftAjax.debug.js. There are some others, but that’s the main part of the client-side framework. But more often than not, you don’t need the entire framework. It contains a lot of features, like support for WebServices, History management, and Globalization. In 4.0, we have split MicrosoftAjax.js into several parts. When you use Explicit mode, you include these scripts manually in order to ‘pick and choose’ what parts of the framework you need, thus reducing the overall size of the javascript your page requires.

  • MicrosoftAjaxCore.js (contains the type system like registerClass)
  • MicrosoftAjaxComponentModel.js (contains Sys.Application, Sys.Component, Sys.UI.Control, as well as DomEvent for event abstraction and DomElement helpers)
  • MicrosoftAjaxNetwork.js (contains WebRequest and WebRequestManager related classes)
  • MicrosoftAjaxWebServices.js (contains WebServiceProxy and is used to talk to asmx and wcf services, or any service that can serve JSON)
  • *MicrosoftAjaxApplicationServices.js (talks to the Profile, Role, and Authentication services)
  • MicrosoftAjaxSerialization.js (contains the JavaScriptSerializer class)
  • MicrosoftAjaxHistory.js (contains extensions to Sys.Application to add client-side history management support)
  • MicrosoftAjaxGlobalization.js (contains formatting and parsing logic for culture-aware Date, Number, String conversion)

MicrosoftAjax.js still exists, too, which is now considered a composite script of all these scripts. The one (*) exception is that MicrosoftAjaxApplicationServices.js is now its own script, not part of MicrosoftAjax.js, and so must be included explicitly even if you don’t use Explicit mode and you want to use any of the application services.

Keep in mind when using this mode that you are “on your own” with determining which parts of the framework you need. This is strictly for those of you who want to lower the footprint of your pages by a little bit. MicrosoftAjax.js in ASP.NET 4.0 is somewhere around 98kb, which is gzipped when served, which takes it down into the 30kb range (numbers from memory – and by the way, these numbers are lower in the recently announced ASP.NET Ajax Beta release on CodePlex by the CodePlex foundation). By comparison, jQuery is something like 20kb once gzipped. So it’s not going to make a big difference, but every bit counts! You can use the existing CompositeScript feature of ScriptManager to include the separate parts of the framework and yet still have them served as a single script.

Oh – yes, these scripts are all also on the CDN and work with EnableCdn, of course.

Replacing System.Web Scripts

When a script component on the page requires an ajax script, it implements the IScriptControl interface, which allows it to tell ScriptManager what scripts it requires. Typically a component will ship with its scripts embedded in its own assembly. In previous versions, you could use a statically declared ScriptReference to override the script used by that component. For example, if a component used the ‘Foo.js’ resource from the ‘CustomControls’ assembly, you could replace the resource based script reference with a static (and possibly, customized) copy like so:

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Name="Foo.js" Assembly="CustomControls"

            Path="~/scripts/customfoo.js" />

    </Scripts>

</asp:ScriptManager>

(In red to indicate this is not a new feature)

One problem with this feature was that it only worked for scripts that were registered via ScriptReferences or through the IScriptControl interface. But some components still use ClientScript.RegisterClientScriptResource or ScriptManager.RegisterClientScriptResource. The controls in System.Web for example, like the TreeView, GridView, etc. If you wanted to replace one of those scripts with a static copy, you couldn’t (actually for System.Web scripts there was a way, but as a legacy feature I won’t go into). Now in 4.0, you can. So for example – if you find a bug in WebUIValidation.js for a Validator control in System.Web, or there’s just something about it you don’t like – or even, you want to customize it for some reason, just override the reference:

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web"

            Path="~/scripts/customWebUIValidation.js" />

    </Scripts>

</asp:ScriptManager>

An interesting benefit to this is that it is now possible to ScriptManager’s CompositeScript capabilities to combine System.Web scripts! If you are using a GridView and a Validator, for example, you will by default get two WebResource.axd’s to Gridview.js and WebUIValidation.js. Most likely you will also get WebForms.js which has some postback logic in it. Now you can combine them into one:

<asp:ScriptManager runat="server">

    <CompositeScript>

        <Scripts>

            <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" />

            <asp:ScriptReference Name="GridView.js" Assembly="System.Web" />

            <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" />

        </Scripts>

    </CompositeScript>   

</asp:ScriptManager>

Now, that is still going to render as an 'AXD' script -- to ScriptResource.axd. The scripts still live in an assembly, after all. But a feature you probably didn't know about with CompositeScripts (and has been there since ASP.NET 3.5 SP1) is that you can point them at static paths just like regular ScriptReferences. For ultimate in performance and a clean HTML rendering, you can not only combine all those scripts into one, but have them referenced via a simple static script block too. No more 'AXD' with a long, encrypted query string.

<asp:ScriptManager runat="server">

    <CompositeScript Path="~/scripts/combined.js">

        <Scripts>

            <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" />

            <asp:ScriptReference Name="GridView.js" Assembly="System.Web" />

            <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" />

        </Scripts>

    </CompositeScript>   

</asp:ScriptManager>

Simple Assembly Names

A small but welcomed addition. Previously, if you wanted to reference a script embedded in an assembly via a static script reference, you had to include the full assembly name in the ‘assembly’ attribute. If the assembly is a strong named one, that meant including the fully qualified named, including the publicKeyToken which you undoubtedly would have to lookup somewhere (although I have a friend who has memorized his company’s publicKeyToken! LOL). Something like this:

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Name="Foo.js"

        Assembly="CustomAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    </Scripts>

</asp:ScriptManager>

Now you can just use simple assembly name. The caveat to this is you do at least need to have the assembly in your bin, or it must be referenced in the <assemblies> section of your web.config. Otherwise, the simple name could be ambiguous to multiple versions in the GAC. In the previous example, notice I used only ‘System.Web’ when overriding WebUIValidation.

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Name="Foo.js" Assembly="CustomAssembly" />

    </Scripts>

</asp:ScriptManager>

ScriptResourceMapping

This is definitely my favorite new feature, so I saved it for last. Normally, ScriptManager determines where to get a script from by looking at the Name, Assembly, and Path properties. Name and Assembly go together to indicate an embedded resource in the assembly, and Path is just a path to a static script in your application. Since the beginning, you could override an assembly-based reference with a path-based reference. For example, to get MicrosoftAjax.js to load from a path in your site rather than from an assembly, you could declare a script reference like so:

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Name="MicrosoftAjax.js" Path="~/scripts/MicrosoftAjax.js" />

    </Scripts>

</asp:ScriptManager>

The assembly is assumed to be System.Web.Extensions if not specified. With this script reference, now even if script controls on the page registered a requirement for MicrosoftAjax.js, this one would be recognized as the same script thanks to the Name being the same. A static reference on ScriptManager trumps all, so your custom path wins, thus replacing the assembly reference with a path one (and worth noting – it still supports auto switching to the debug version and to localized versions).

Great – there are some problems to consider:

  1. What if I want every page in my app to do this? If you’re using a Master Page, you may only have a few ScriptManager’s to deal with, so that may not be so bad. But even then, there’s a maintenance factor here.
  2. What if I am using a 3rd party component and it does not define a CdnPath? Is there any way to make it work with EnableCdn if I can host it somewhere myself?
  3. What if I want to change which CDN is used for a particular resource (remember, we hard coded the path earlier)?
  4. How can I get the benefits of automatically switching between debug and release scripts for a non assembly-based resource?
  5. How can I get the benefits of automatically switching between debug and release scripts for a script like jQuery that does not use the “.debug.js” naming convention?

To be fair, #4 was already possible by explicitly setting the ScriptMode property on the script reference – but we’ll see a better way now.

ScriptResourceMapping to the rescue. Think of ScriptResourceMapping as a static/global location into which you can describe all the details about a particular script resource: a logical name for the script, it’s debug and release locations, what assembly it lives in (if any), and what it’s debug and release CDN paths are. With all that information, ScriptManager can make smarter choices about how to handle a script reference and makes your life easier.

For example, let’s say you want to include jQuery via a ScriptReference.

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Path="~/scripts/jQuery-1.3.2.js" />

    </Scripts>

</asp:ScriptManager>

But wait – what about jQuery-1.3.2.min.js? You should definitely be using the minimized version in production. But in a debugging environment, it’s better to use the non-minimized version so if you ever need to step into jQuery code, you can actually understand what is going on.

And what about EnableCdn? That’s not going to work with this since ScriptManager doesn’t know about this script. It’s just some script in your project. Yes, you could just put the full ‘http://...’ path in there. But having to remember that path every time you need it is not very nice.

No problem – we’ll just create a mapping that fully describes the resource. Mappings are static, so let’s create them from the Application_Start event in Global.asax:

void Application_Start(object sender, EventArgs e) {

    // map a simple name to a path

    ScriptManager.ScriptResourceMapping.AddDefinition("jQuery", new ScriptResourceDefinition {

        Path = "~/scripts/jquery-1.3.2.min.js",

        DebugPath = "~/scripts/jquery-1.3.2.js",

        CdnPath = "http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js",

        CdnDebugPath = "http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.js"

    });

}

Three big wins here.

  1. Now I can simply reference jQuery by name, just like MicrosoftAjax.js (only I don’t even need the ‘.js’ part).
  2. Because ScriptManager knows the path to jQuery’s release and debug versions, it switches automatically just like it does for MicrosoftAjax.js.
  3. Because ScriptManager knows jQuery’s CdnPath, the EnableCdn feature will toggle using it on/off just like it does for MicrosoftAjax.js.

Using this mapping is simple – just reference the script by name:

<asp:ScriptManager runat="server">

    <Scripts>

        <asp:ScriptReference Name="jQuery" />

    </Scripts>

</asp:ScriptManager>

Beautiful. You can use this to redefine the CdnPath for an existing script, too. For example, say you don’t like the fact that MicrosoftAjax.js loads from the ajax.microsoft.com Cdn. Or, say you are using some 3rd party controls, and they don’t define a CdnPath, but you happen to know of one that uses it (or even, the 3rd party published a Cdn after they shipped the product). Just create a mapping and set the CdnPath. Done. For the entire application.

But wait, there’s even more. The jQuery example shows how you can map a simple name to a static script. But a script resource mapping can also be used to map a name to an assembly resource.

// map a simple name to an assembly

ScriptManager.ScriptResourceMapping.AddDefinition("Foo", new ScriptResourceDefinition {

    ResourceName = "FooResource.js",

    ResourceAssembly = MyAssembly

});

Or, map an existing assembly resource to a static path.

// map assembly resource to a path

ScriptManager.ScriptResourceMapping.AddDefinition("SomeScript.js", SomeAssembly,

    new ScriptResourceDefinition {

        ResourceName = "SomeScript.js",

        ResourceAssembly = SomeAssembly,

        DebugPath = "~/scripts/somescript.debug.js",

        Path = "~/scripts/somescript.js"

});

Or, map an existing assembly resource to a different assembly resource.

// map an assembly resource to another assembly resource

ScriptManager.ScriptResourceMapping.AddDefinition("SomeScript.js", SomeAssembly,

    new ScriptResourceDefinition {

        ResourceName = "SomeOtherScript.js",

        ResourceAssembly = MyAssembly

    });

Don’t forget you can also use this to change where the MicrosoftAjax*.js scripts come from.

This gives you a lot of control over where scripts come from. Now your pages can utilize ScriptManager’s advanced features, without necessarily depending on MicrosoftAjax.js, and without having to hard code paths to scripts or to assembly resources. Now your pages can be a semantic definition of the scripts your page requires – and the details are all in one location. And when the need arises, you can change where those scripts come from, no matter where they came from originally.

Bringing it all together: De-AXD’ifying

Not really a feature of it’s own – but a consequence of the others worth noting. Because ScriptManager can now deal with System.Web scripts or any scripts regardless of which API is used to register them, it is now possible – for the first time – to get rid of all WebResource.axd and ScriptResource.axd urls from the HTML rendering. And you can do it without touching your pages due to the ScriptResourceMapping feature. And what’s more – because of the CompositeScript feature, you can also get them all combined into a single, static script file, with a simple, beautiful url. Or better yet – let Microsoft handle the bandwidth, and use the CDN!

Preview 5 of the Microsoft Ajax 4.0 library has been released. Some quick background – this the next version of the client-side ajax framework you have probably already heard of, the one that ships along with ASP.NET 3.5 (but is also available in script form). The fact it ships with ASP.NET has sometimes led to it being called the ASP.NET AJAX Framework. Technically, that name is a superset – it encompasses “Microsoft Ajax” and it’s ASP.NET specific, server-side features, like the ScriptManager. But “Microsoft Ajax” always has and always will be an ajax framework that is not tied to any specific server-side technology. Also noteworthy is that this 4.0 library can run on top of ASP.NET 3.5, replacing the 3.5 version it normally uses.

In previous previews of Microsoft Ajax 4, we introduced the DataView control. It’s a simple but powerful control that takes advantage of the client templating engine we built for it. You point it at a template, and some data, and it instantiates the template for each item in the data. The templating engine lets you use ‘placeholders’ and create ‘live bindings’ between the rendered DOM elements and the data, as well as allow you to attach other ajax components and controls.

I want to focus on one of the new features added to the DataView in preview 5, but first, I feel obliged to introduce the DataView control from a basic level, since most of you probably don’t know about it yet.

Simple DataView Example

As a simple example – lets make up some data. Normally this would come from a web service or some other source, not hard coded, of course.

var stockData = [
    { symbol: "DJIA"  , change: 79.88, value: 9627.48 },
    { symbol: "NASDAQ", change: 23.63, value: 2084.02 },
    { symbol: "AAAA"  , change: -0.22, value: 27.56 },
    { symbol: "BBBB"  , change: -1.46, value: 82.12 },
    { symbol: "CCCC"  , change: 0.67 , value: 7.56 }
];

We want to show this stock data in a table, and probably do some formatting to show the values as currency, etc. Without a templating engine, you’d basically either have to painstakingly create DOM elements by hand, or build up a string and use innerHTML. Neither technique is easy to maintain, or are designable by designer tools. Worse, building a string and using innerHTML could net you some XSS vulnerabilities. This is where the templating engine in Microsoft Ajax 4 comes in.

<table id="stocks" class="stocks sys-template">
    <tr>
        <td>{{ symbol }}</td>
        <td>{{ value.localeFormat("c") }}</td>
        <td>{{ change.localeFormat("c") }}</td>
        <td>{{ (change/value).format("p2") }}</td>
    </tr>
</table>

In the simple form, {{ foo }} represents a placeholder where the value of a field named ‘foo’ from the data items will be. What language is this stuff? Just javascript. So as you can see, this take advantage of the formatting methods in Microsoft Ajax to convert the values to currency. You could write any ole javascript here, of course (unobtrusive javascript alert: yes, you can do it that way too, more on that later).

The class “sys-template” is setup to have display:none, so that this chunk of HTML doesn’t actually show up in the markup.

That’s the template – it represents what each item should look like. Now to put it to use with the DataView control:

function pageLoad() {
    $create(Sys.UI.DataView, {
        data: stockData
    }, null, null, $get("stocks"));
}

That’s it. The DataView control is given the data, and the template. Everything is hooked up. Here is the result (css not shown):

image 

One obvious improvement we could make to this sample is to dynamically style the rows so that stocks going up are green, down, red. You can in fact do that, but I digress. This is just the most basic use of a DataView. I haven’t even mentioned live bindings. And even in preview 4 you could reuse templates across multiple dataviews, and set the placeholder to be something other than the default. Here is an excellent article by Jim Wang which covers some of the other things you could do in Preview 4, including selecting items, and integrating with an ADO.NET DataService.
http://weblogs.asp.net/jimwang/archive/2008/11/05/working-with-ado-net-data-services-in-ajax.aspx

Preview 5 – Dynamic Templates and Dynamic Placeholders

Preview 5 introduces a new feature to the DataView control that allows you to dynamically determine the template used for each data item, as well as dynamically determine the placeholder that anchors where it will be inserted. This means each data item can potentially render completely differently, and render into completely different areas of the page, all the while being under the control of a single DataView!

What does this mean? Well, say you have a single set of data returned by a service of some kind. But you don’t want to simply list this data all in one place. Some needs to go there, and some over there, depending on the state of each item. A typical example of this might be a data set of forum posts, where some of them are marked as ‘sticky’, and so should be listed first, but the sticky ones aren’t necessarily first in the list of data. How would you normally deal with that? Separate the sticky items into their own data set, or query for them separately? If you are using stored procedures, maybe that means creating a new one or modifying an existing one to support the filtering. Why go through such hoops and database-level manipulations when this is purely a UI problem? If it can’t be solved by your UI tools, perhaps you’re blurring your separation of concerns.

So as an experiment, I imagined a list of bloggers. Each blogger may or may not be on Twitter, right? But I want the tweeting and non-tweeting bloggers to be listed separately. Furthermore, the way I display a tweeting blogger and a non-tweeting blogger may be very different. For one, I want to display some of the latest tweets from the tweeting bloggers, and display their Twitter avatar.

Mind you, it is certainly possible to use dynamically determined css classes, and to dynamically show/hide regions of content within a template, based on the data item. But that only gets you so far. Sometimes, the differences are too much to neatly define a single template that can represent either kind of data item. This particular example could have been done either way. Maybe I just wasn’t creative enough :)

First – let’s define our bloggers.

var bloggerList = [
    { name: "InfinitiesLoop", author: "Dave Reed",
        uri: "http://weblogs.asp.net/infinitiesloop", twitter: "infinitiesloop" },
    { name: "Computer Zen", author: "Scott Hanselman",
        uri: "http://www.hanselman.com/blog", twitter: "shanselman" },
    { name: "Random Thoughts", author: "Bob",
        uri: "http://myblog.com" },
    { name: "Tales from the Evil Empire", author: "Bertrand Le Roy",
        uri: "http://weblogs.asp.net/bleroy", twitter: "bleroy" },
    { name: "The Gu", author: "Scott Guthrie",
        uri: "http://weblogs.asp.net/scottgu", twitter: "scottgu" },
    { name: "Some blog", author: "Mr. IDontTwitter",
        uri: "http://weblogs.asp.net/donttwitter" },
    { name: "Jim Wang's Blog", author: "Jim Wang",
        uri: "http://weblogs.asp.net/jimwang/", twitter: "turanuk" },
    { name: "James Senior", author: "James Senior",
        uri: "http://www.jamessenior.com/", twitter: "jsenior" }
];

Each blogger has a blog name, author name, uri, and if they have one – a twitter id. Important to note – the non-twittering bloggers are not at the beginning of the array, they are mixed in with the others.

For brevity I’m going to show the declarative way of attaching a DataView control, even though we feel most developers would prefer to keep this stuff separated from their markup. Everything you see here can be done in pure code (imperatively). And we are actively working on some very interesting improvements that make the imperative ways much, much easier than they are in Preview 5, so stay tuned, you won’t want to miss it. Both declarative and imperative approaches are in the sample download at the end of this post.

Let’s first define the overall structure we want:

<div id="bloggers" class="bloggers"
    sys:attach="dv" dv:data="{{ bloggerList }}"
    dv:onitemrendering="{{ itemRendering }}">
    <div class="notwitter">
        Non-twittering Bloggers
        <ul>
            <li id="normalph"></li>
        </ul>
    </div>
 
    <div class="hastwitter">
        Twittering Bloggers
        <ul>
            <li id="twitterph"></li>
        </ul>
    </div>
</div>

Two divs, one for each kind of blogger. And placeholders for where each should be rendered. A DataView is attached declaratively with sys:attach=”dv” (the ‘dv’ comes from an xml namespace declared on the documents body tag and maps the namespace ‘dv’ to the Sys.UI.DataView class, ‘dv’ is not magical). As each blogger is processed, the ‘itemRendering’ event is fired before anything is instantiated for it. We’ve hooked up a handler for it:

function itemRendering(dv, args) {
    var blogger = args.get_dataItem();
    if (blogger.twitter) {
        args.set_itemTemplate("twitterblogger");
        args.set_itemPlaceholder("twitterph");
    }
    else {
        args.set_itemTemplate("normalblogger");
        args.set_itemPlaceholder("normalph");
    }
}

If the blogger has a Twitter id, we set the template to the ‘twitterblogger’ template and tell it to render where the ‘twitterph’ element is. Otherwise, we use the ‘normalblogger’ template and render them where the ‘normalph’ element is. For a ‘normal’ blogger, we just want to render a link to their blog and their name:

<ul class="sys-template" id="normalblogger">
    <li>
        <a sys:href="{{ uri }}">{{ name }}</a>
        <span>author: {{ author }}</span>
    </li>
</ul>

Pretty simple. For a tweeting blogger, we want to do something slightly different, plus we want to show their last 5 tweets for good measure.

JSONP

Another feature in Microsoft Ajax 4, I should mention, is JSONP support. And good thing too, because it makes this demo way cooler. Twitter happens to have a JSONP service, and the DataView integrates nicely with the networking support in Microsoft Ajax, giving it JSONP support, too. So getting tweets for someone is just a matter of creating a DataView with the JSONP address as the ‘dataProvider’. So our Blogger DataView is going to actually contain a nested DataView. Here is the ‘twitterblogger’ template:

<ul class="sys-template" id="twitterblogger">
    <li>
        <a sys:href="{{ uri }}">{{ name }}</a>
        <span>{{ author }}</span>
        <ul class="tweets sys-template" sys:attach="dv" dv:autofetch="true"
            dv:dataprovider="{{ getTwitterUrl(twitter) }}">
            <li>
                <img class="avatar" sys:src="{{ user.profile_image_url }}" alt="" src="" />
                {{ text }}
            </li>
        </ul>
    </li>
</ul>

So, our blogger entry has a nested UL, to which we attach another DataView with the JSONP Twitter url as the target provider. The data returned from Twitter also has information about the Twitter user, like their avatar, so we may as well show that, too. The ‘getTwitterUrl’ call demonstrates that you aren’t limited to just data – you can do stuff with it too. That method simply takes the blogger’s Twitter id and constructs the JSONP service url for their last 3 tweets.

That’s it! Here it is in action:

image

Download the sample code here.

Also, be sure and check out these other awesome posts about Microsoft Ajax 4.

These are based on previous preview releases.

There’s a lot of debate these days about the ASP.NET WebForms model vs. the newer ASP.NET MVC model. There are advantages to both. Disadvantages to both. Pick the one that best fits your needs. Nuff said. But sometimes that choice isn’t so obvious.

MVC for example essentially gives you much more control over the generated HTML for the page. Well, complete control. But sometimes you don’t really need complete control, and the lack of an encapsulated control kind of sucks. HTML Helpers help, but they have no design time experience. Hence, there are the MVC Controls in the MVC Futures project on CodePlex and an interesting compromise between the two models, at least when it comes to the rendering part of the application.

But then there’s the other side of the equation – you’ve got a WebForms application, and you need a little more control over the HTML. What’s the compromise there? Well, server controls try to give you control over the markup. Some of them do a pretty good job at it, like the ListView control added in ASP.NET 3.5. Others, not so good. If a control doesn’t let you do what you need, you are pretty much stuck – either abandon the control and all its usefulness, or write your own control.

What’s in a control anyway?

If you think about it, controls at the highest level are really two very different things.

  1. Controls abstract the rendering of HTML.
  2. Controls provide client-server integration by managing data between client and server.

Take the CheckBox control. It renders an input and label, and connects them with the ‘for’ attribute, so clicking the text also checks and unchecks the checkbox. That’s it’s HTML abstraction. It provides client-server integration by allowing you to dynamically read and write to the checked property on a server-side proxy.

A simple example of #2 is the TextBox control. Double meaning, uh, not intended. Type some text into the box and submit the form – magically, the server-side instance knows what its Text property should do. The control can also push data back to the client. Set the Text property, and magically the value is reflected in the rendered page. This can be much more complex though – the control might manage a hidden field, or rely on data stored in that catch-all hidden field we love to hate, ViewState.

The thing is, HTML abstraction is useful, but a lot of the time it doesn’t provide a ton of benefit. Client-server integration, however, is usually much more useful. If you don’t need that there’s a good chance you don’t need a control to begin with.

Html Controls

I would be wrong not to point out that there’s a whole namespace of controls in ASP.NET that are largely underused. HTML controls allow you to add a runat=”server” to an HTML element and get reasonable client-server integration with it. So if you don’t like how the CheckBox control renders, just use the HtmlCheckBox instead. But what if you’re using a more complex control that has no HTML equivalent?

What if you could control the HTML for any server control without losing the client-server interaction?

Wouldn’t that be nice?

Taking Control

Introducing the CustomRender control. This control suppresses the rendering of any control(s) you put in it, while allowing you to define your own, replacement HTML. It gets a little nicer than that, though. One step at a time – first, lets choose the enemy. A Button control that sets the text of a Label control.

<script runat="server">
    private void ButtonClick(object sender, EventArgs args) {
        Label1.Text = "You clicked Button1";
    }
</script>
<asp:Button ID="Button1" runat="server" Text="Go" OnClick="ButtonClick" />
<asp:Label ID="Label1" runat="server" />

You’re going down, Button1. Bring on the CustomRender:

<i88:CustomRender runat="server">
    <ControlTemplate>
        <asp:Button ID="Button1" runat="server" Text="Go" OnClick="ButtonClick" />
        <asp:Label ID="Label1" runat="server" />
    </ControlTemplate>
</i88:CustomRender>

That’s step 1. Now how do we get our own HTML in here? As this stands, the button and label will not render anything. They still participate in the page lifecycle and all that goodness. But nothing renders. So we could just put the HTML next to the CustomRender control. But it would be nice if this control helped me out a little by giving me what these controls would have rendered, wouldn’t it? Lets swap over to Design View.

If you’re one of the types that never uses Design View – it’s that button that says ‘Design’ on the lower left, or Shift-F7.

image

Click on “Update HtmlTemplate”, then switch back on over to Source view. Voila…

<i88:CustomRender runat="server">
    <ControlTemplate>
        <asp:Button ID="Button1" runat="server" Text="Go" OnClick="ButtonClick" />
        <asp:Label ID="Label1" runat="server" />
    </ControlTemplate>
    <HtmlTemplate>
        <input ID="Button1" name="Button1" type="submit" value="Go" /> <span ID="Label1">
        </span>
    </HtmlTemplate>
</i88:CustomRender>

The designer for the control has rendered its ControlTemplate and put the result into the HtmlTemplate. And just to prove it works, modify the HTML a little. Lets change the ‘value’ of the input from ‘Go’ to ‘Gone’.

image

And now lets click the button and see if the server control still works. Remember, it’s supposed to set the text of the label to “You clicked Button1.”. Hmmmm.. nothing. It broke!!! No… remember, when you do this, you take complete control over the HTML. That text doesn’t just come from no where. The code is running, but you haven’t put it into your HTML.

How do you do that? No problem – think of the HTML template like a mini-MVC View.

<HtmlTemplate>
    <input ID="Button1" name="Button1" type="submit" value="Gone" />
    <span ID="Label1"><%= Label1.Text %></span>
</HtmlTemplate>

Now when we click the button, it works:

image

Show Off – The Challenge

“Okay,” you say, “but that’s just a button and a label. What about a real world scenario,” you spout in disbelief? I dunno if you said that, but it’s more interesting to pretend like you are challenging me to put this technique to the test. I accept your pretend challenge.

Way back in ASP.NET 1.x there was the DataGrid control. As great as it was at the time, it’s limitations eventually led to the GridView control. As great as that was, you still didn’t get enough control over the markup and CSS, so the ListView control was born (I often wonder what we’d call the next iteration – running out of two-word data-like combinations aren’t we? No, there already is a DataList control!). My point being that in the current set of databound controls, the DataGrid control is probably the oldest and most set in its ways, and most known for its lack of customizability. It renders as a <Table>, and that’s that. How 1990’s of it.

A perfect target for the challenge – let’s do the unthinkable. Get a DataGrid to render as <UL> and <LI> and be styled with 100% CSS, while maintaining the server-side features like SelectedIndex.

First, lets take a look at a DataGrid utilizing the SelectedIndex feature.

<asp:DataGrid ID="dg1" runat="server" 
    AutoGenerateColumns="false" SelectedIndex="1" SelectedItemStyle-CssClass="selected"
    DataSource='<%# DummyData %>'>
    <Columns>
        <asp:BoundColumn DataField="Name" />
        <asp:ButtonColumn DataTextField="Price" DataTextFormatString="{0:c}" CommandName="Select" />
    </Columns>
</asp:DataGrid>

It shows two columns – a product name, and a price, formatted as currency. You can click on the price to select the item, which then has a different CSS class. The DummyData property is just returning an ArrayList with a few sample items. Let’s not forget how you databind this thing… you may be using a DataSource control. For this purpose we’ll just do it the old fashioned way.

protected override void OnLoad(EventArgs e) {
    if (!Page.IsPostBack) {
        dg1.DataBind();
    }
    base.OnLoad(e);
}

Now lets take a look at the rendering.

<table cellspacing="0" rules="all" border="1" id="dg1" style="border-collapse:collapse;">
    <tr>
        <td>&nbsp;</td><td>&nbsp;</td>
    </tr><tr>
        <td>Widget</td><td><a href="javascript:__doPostBack('dg1$ctl02$ctl00','')">$19.95</a></td>
    </tr><tr class="selected">
        <td>Horn</td><td><a href="javascript:__doPostBack('dg1$ctl03$ctl00','')">$2.99</a></td>
    </tr>
</table>

image

A few things of note going on here. For the SelectedIndex feature to work, the ButtonColumn has rendered an <A> tag which does a postback. The ID it passes to the __doPostBack function is the UniqueID of a link button it has added to the control tree. The LinkButton raises a bubble command named “Select”, which the DataGrid picks up and sets its SelectedIndex property. While rendering, the DataGrid applies a different style to the selected item.

Translating this into your own custom HTML is pretty easy actually. The trick is to do rendering only – you could in theory use a Repeater to bind over the same items. We’re trying to leverage the existing features of the DataGrid, so rather than grab the data directly we’re enumerate the DataGrid’s Items collection and try to reuse as much as we can.

Again, think of this template as a mini-MVC view, and the actual control we are targeting is like our ViewData. That way, changes to the DataGrid don’t require changes to the custom rendering.

<i88:CustomRender runat="server" ID="c1">
    <ControlTemplate>
        <asp:DataGrid ID="dg1" runat="server" SelectedItemStyle-BackColor="Red"
            AutoGenerateColumns="false" SelectedIndex="1"
SelectedItemStyle-CssClass="selected"
            DataSource='<%# DummyData %>'>
            <Columns>
                <asp:BoundColumn DataField="Name" />
                <asp:ButtonColumn DataTextField="Price"
DataTextFormatString="{0:c}" CommandName="Select" />
            </Columns>
        </asp:DataGrid>
    </ControlTemplate>
    <HtmlTemplate>
        <% for (int i = 0; i < dg1.Items.Count; i++) {
               // enumerate the DataGrid's items so we can choose how to render them
               var item = dg1.Items[i];
               // the ButtonColumn is rendering a LinkButton or Button 
               var priceLink = (IButtonControl)item.Cells[1].Controls[0];
               %>
        <ul class="item<%= dg1.SelectedIndex == i ? " selected" : "" %>">
            <li><%= item.Cells[0].Text %></li>
            <li class='price' 
onclick="<%= Page.GetPostBackEventReference((Control)priceLink) %>">
<%= priceLink.Text %>
</li>
        </ul>
        <% } %>
    </HtmlTemplate>
</i88:CustomRender>

A for loop enumerates the DataGrid.Items collection. For the first column we just repeat the cell’s text. The 2nd column is more complex as it contains a LinkButton with a postback reference. Even so, it’s not too complex – get a reference to the LinkButton and use Page.GetPostBackEventReference() to generate the necessary postback script. We are now free to apply CSS in anyway we like. Watching for the the SelectedIndex, we apply a ‘selected’ class, for example.

I’ve just quickly put together these styles to make each ‘item’ float left, so the “grid” isn’t even a grid anymore, just to show how it can be totally different.

<style type="text/css">
    ul.item {
        float: left;
        list-style-type: none;
        padding: 0px 10px 0px 10px;
    }
    ul.selected {
        border: solid 1px red;
    }
    li.price {
        cursor: pointer;
        color: Blue;
        text-decoration: underline;
    }
</style>

And here it is running.

image

Mission Accomplished

Perhaps you are thinking that is pretty ugly and difficult. If you are, remember that is why controls abstract that stuff away for you, so it’s easy and expressive. This is by no means “the end” of control rendering. It’s a tool you should keep in your toolbox. If you have a difficult to fix rendering issue for a specific control, now you don’t have to say goodbye to the whole thing.

How does it work?

It’s actually pretty simple! All controls create their HTML in the Render() method. To control the HTML, you just need a way of injecting your own HTML while suppressing the stuff it’s Render() method produces. Ok – so, don’t call Render(). The Render method unfortunately does not only produce HTML. Sometimes it produces script references or “startup” scripts. Sometimes it registers with the ASP.NET Event Validation feature for security purposes. So this control still calls Render, but it throws away the resulting HTML. It instantiates the ControlTemplate like any other template, adding it to its own control tree so they particulate in the lifecycle. It just chooses to actually render the HTML template instead. That is, unless it is design time. Then it renders the control template – allowing you to use the controls in the designer like you normally could.

Gotchas

Controls will not necessarily take kindly to being rendered “for reals” at Design Time. The page isn’t real, and the other controls on the page don’t necessarily exist or are in their proper hierarchy. So the “Update HtmlTemplate” designer action may not always work. It might even cause an exception to be thrown. It depends on the control.

Also, I find that although the correct HTML is being rendered internally, VS gets it’s hands on it and makes a few modifications to the persistence of it for some reason. It seems mostly benign, like reordering element attributes. But one bad thing it does is capitalize the ‘id’ attribute, which is supposed to be in lower case if you care about XHTML compliance. Easy enough to fix once you get the HTML bootstrapped. I’m trying to find out from someone on the team why this happens and if we can fix it. If all else fails, you can always run the page and use the actual source to get the HTML rather than use the designer trick.

Download & Discuss

It’s up on code gallery, including the sample of the world’s first cannibalized DataGrid.

http://code.msdn.microsoft.com/aspnetcustomrender

Looking for an ASP.NET AJAX book? This one has been massively updated from its 2.0 version, to cover in detail the features added in 3.5, and not to be forgotten, 3.5 SP1. For example, Script Combining was a new feature in 3.5 SP1, and so was History support, so it's an important distinction! The 2.0 book was 307 pages, and this one is 552. History support, by the way, has a dedicated chapter. Script combining is a major portion of the chapter on the ScriptManager.

 Another important difference between the 2.0 and 3.5 versions -- this time, I'm a contributing author. :) My first major technical publication, hopefully more to come. I'm that weird guy on the right.

http://www.amazon.com/Professional-ASP-NET-AJAX-Bill-Evjen/dp/0470392177

I ran into an interesting and unexpected behavior in ASP.NET AJAX event handling the other day. Once I figured out what was going on, I was almost positive it was a bug, so I started looking into what a solution would be. But just out of curiosity, I looked at what the behavior was for a server-side event. Much to my surprise, the behavior was the same. The behavior then was consistent with the server-side behavior, not a bug. But is it the "correct" behavior? Tell me what you think...

To put it in the most shocking way possible: Removing a handler from an event does not guarantee that handler will not be called when the event fires!

SACREBLEU!!

But it's true. Take a look at this code...

public class Bar {
    public event EventHandler SomeEvent;
 
    public void RaiseEvent() {
        if (SomeEvent != null) {
            SomeEvent(this, null);
        }
    }
}
 
public class Foo {
    private Bar _bar;
    private EventHandler _handler;
    private ArrayList _list;
 
    public void Initialize(Bar bar) {
        _bar = bar;
        _list = new ArrayList();
        // listen to the event on bar
        _handler = new EventHandler(OnSomeEvent);
        _bar.SomeEvent += _handler;
    }
 
    private void OnSomeEvent(object sender, EventArgs args) {
        // event was raised, do something
        // this cant happen if Stop() was called.... right?
        _list.Add("blah");
        Console.WriteLine("OnSomeEvent");
    }
 
    public void Stop() {
        // tidy up, stop listening to the event and clear the list
        _bar.SomeEvent -= _handler;
        _list = null;
    }
}

Now, this is a totally contrived example, so the code here isn't exactly useful. But the basic idea can occur in a real program. Here, there's a Bar component that exposes an event, SomeEvent. Normally a component raises it's event when appropriate and doesn't have an actual RaiseEvent() method to raise it, but for demo purposes, it's got one so we can fire the event later on.

The Foo component has two public methods -- Initialize, and Stop. Initialize takes a Bar component, and it adds an event listener to the event. Stop removes the event listener, since after all, it is important to clean up after yourself when it comes to events. If the handler was never removed, the Bar component will forever have a reference to the Foo, and Foo will live as long as Bar lives.

When the SomeEvent fires, Foo adds to an ArrayList which it has internally created. Notice in Stop() it sets the ArrayList to null. The event handler OnSomeEvent adds to the list without checking it for null.

If somehow the event handler were called even after Stop(), we'd have a null reference exception! Can't happen, right? When you think about a typical use of these components, it doesn't appear to be possible... Here would be one way of raising the event and removing the handler.

public class Program {
    public static void Main(string[] args) {
        Bar bar = new Bar();
        Foo foo = new Foo();
 
        foo.Initialize(bar);
        bar.RaiseEvent();
        foo.Stop();
 
        Console.ReadLine();
    }
}

image

No problem there. But what if an event handler for SomeEvent removes the event handler of a separate component? Something like this...

public static void Main(string[] args) {
    Bar bar = new Bar();
    Foo foo = new Foo();
 
    bar.SomeEvent +=
        delegate(object sender, EventArgs a) {
            foo.Stop();
        };
    foo.Initialize(bar);
    bar.RaiseEvent();
    foo.Stop();
 
    Console.ReadLine();
}

The result? BOOM...

NullReferenceException

Even though Foo has removed its listener, the listener is called. The reason is because its listener was removed after the event was already underway -- and, I suppose for multi-threaded reasons, once an event begins, the listeners that existed at the time will fire even if they are removed in the process.

Again, this is a very contrived example. But it could happen more innocently and not be so obvious. Perhaps when SomeEvent occurs, under a certain condition, a listener in the application decides to shut down some container which contains a Foo component, and that shutdown process calls Stop() on Foo. The first listener doesn't know that will happen. And Foo doesn't know Stop() was called as a result of an earlier listener to the very event it is unhooking from. Who is supposed to know what is going on?

So be careful, I suppose is the lesson to be learned. If a component may end up removing an even listener as a result of code external to it, it is entirely possible that it is the very event it is removing the listener from that is currently executing and causing it. In that scenario, you shouldn't assume you are safe from the listener being called.

First of all, if you haven't already done so, download the ASP.NET AJAX 4.0 Preview 3 now and try it out! And after you're done with that, come back here, or there, or there, or there, and let us know what you think and what you like or don't like about it. We love feedback, and it really does have an impact on the product. We wouldn't go through all the trouble of releasing preview bits or presenting these things if it didn't.

So, I thought I would detail one of the interesting yet behind-the-scenes features in the 4.0 preview, because on its own it is pretty useful. I say behind-the-scenes, because it is used by and invented for many of the features in the preview, such as Bindings and the DataView control, but it is also a public API that you can use for your own purposes.

A bit about JavaScript Objects

Objects in JavaScript are associative arrays. If you are familiar with the .NET Hashtable or any equivalent data structure in any other language, it's like that. It's a collection of keys and values -- where keys are strings and values are anything (not accurate to say they are 'Objects' since not everything in JavaScript is an Object, like strings).

var obj = new Object();
obj.foo = "string";
obj.bar = new Date();
obj["abc def"] = [1, 2, 3];

Which of course can be expressed a little more compactly:

var obj = { foo: "string", bar: new Date(), "abc def": [1, 2, 3] };

JSON Web Services

When you call a service that returns JSON, you end up with one of these "plain 'ole JavaScript objects". Plain, because there's nothing 'activate' about it. There's no code that runs within the object when you get and set values, etc. In this world of AJAX frameworks and features, it is just a plain object.

But what if you are plugging that data into a component, which then consumes those values. If you ever change any of the values, the component won't know about it unless you tell it. Wouldn't it be nice if the component could be notified of any changes to the object automatically? That way, for example, if you were rendering out a list of Widgets based on an array of POJO objects containing widget data, you could, say, edit the name of one of the widgets and the rendered list could automatically reflect the updated value, without you having to force it or re-render everything. Doing it manually you may think wouldn't be so bad -- but it means coupling logic with UI, or at least deriving some custom mechanism for decoupling them. But there is no mechanism by which you can be notified of changes to a POJO.

var widget = { name: "widget1" };
renderWidget(widget);
widget.name = "newname";
renderWidget(widget);

A possible solution would be to create an actual class to represent a Widget, and bind to that instead. Then instead of saying widget.name =" newname", you can call a method, like widget.set_name("newname"). The code could then execute a callback to notify anyone interested that there is a new name. The problem here is that the web service you called just returned a POJO. So now you have to convert the POJO to this business class object, or wrap it in one. If there is a lot of data, that could be quite expensive and slow, and it just complicates things.

var widget = { name: "widget1" }; // came from a JSON service
var businessObject = new Widget(widget); // warps or converts it
renderWidget(businessObject);
businessObject.set_name("newname");

Introducing Sys.Observer

The Microsoft AJAX 4.0 preview includes this Sys.Observer class that allows you to be notified of updates to POJO's, provided you use its APIs to modify them. It is named observer of course after the Observer design pattern. Used internally by the live bindings feature and the DataView control, it was necessary to support these features without requiring wrapped business objects, but it is so useful on its own we decided to make it public and independent, so you can use it in your own scenarios too. The above example can be expressed like this.

var widget = { name: "widget1" }; // came from a JSON service
renderWidget(widget);
Sys.Observer.setValue(widget, "name", "newname");

Notice the call to Sys.Observer.setValue(). This sets the "name" field on the POJO, but in a manner that knows how to notify any "observers". Ok -- so, how do you become an observer of the object? The pattern is very similar to the INotifyPropertyChanged interface that Microsoft AJAX Components can implement, but without the interface and bloat of implementing a component. The hypothetical "renderWidget" function here could look something like this:

function renderWidget(widget) {
    Sys.Observer.addPropertyChanged(widget, showWidget);
    showWidget(widget);
}
function showWidget(widget, args) {
    $get('div1').innerHTML = widget.name;
}

The Sys.Observer.addPropertyChanged() method "adds" a "propertyChanged" event handler. You can also stop observing the object by removing the handler with Sys.Observer.removePropertyChanged(). When the component changes because someone calls setValue(), the observers are notified by raising the property changed event for that object. The arguments to the callback are just like a typical AJAX event exposed by an AJAX component -- the first is the "sender", the object that raised the event, and in this case that is the widget, and "args" that is information about the event. The "args" is a familiar type that is already in the AJAX framework -- Sys.PropertyChangedEventArgs. From those args you can get the name of the property which as changed (in this case, "name").

An alternate syntax - giving your POJOs just a little MOJO

The "add" and "remove" prefixes are analogous to the "add_" and "remove_" prefixes that AJAX Components use when exposing events. There is no "_" here though, because these methods don't have the typical signature of an AJAX event adder or remover -- they take the object as a parameter, rather than you calling the adder or remover directly on the object. It may or may not seem to you that the syntax for changing a value on the POJO is a bit verbose. The APIs on Sys.Observer are all static, meaning you have to pass in the object (e.g. 'widget') as the first parameter to all of them. The reason for that obviously is that the object does not have any functions on it which you can execute, it is a POJO after all. However, you can optionally "convert" the object to an observable one, which adds the necessary methods to it for you.

var widget = Sys.Observer.observe({ name: "widget1" }); // make pojo observable
renderWidget(widget);
widget.setValue("name", "newname");

What is the difference you ask? Functionally speaking, there is no difference at all. The two methods are equivalent. In fact, internally the one just calls the other. Practically speaking, converting the object to be an observable object may be convenient in certain cases, but also has the side effect of adding "gunk" onto the plain object. It is no longer a "plain" JavaScript object, since it now has some actual meat on it.  But, just a little bit. Not enough that it loses its "simplicity" that the "P" in POJO gives you. Just a little meat on its legs. I guess that makes it a MOJO, "meaty 'ole JavaScript object" :) But hey, the choice is yours! By the way, none of the internal usage of Sys.Observer calls observe(), so the framework itself will never "gunkify" your POJOs automatically. We made sure of that, we know you are very fond of your POJOs and you don't want some presumptuous framework messing with them and turning them into MOJOs. Ok then.

What about Sys.Observer.getValue()? It doesn't exist. It really doesn't need to -- you can get the value directly off the POJO. No need for the indirection.

What about JavaScript Arrays?

This is great and all, but JSON web services don't return a single widget. They return a lot of widgets, usually. So you are dealing with, uhh, a POJA... a "plain ole javascript array". That's right -- a POJA. You heard it here first. Kind of abusing the POJO term here, but for a good reason -- we COULD have a fat collection type class in the AJAX Framework, but we don't. Arrays have the same problem POJOs have, in that any time they are added to or removed from, there is no logic behind that operation, so there's no way for interested observers to realize when the array has been modified automatically (at least, not without a polling operation).

Observing POJAs

Some of the logical operations you can perform which modify the array using the various JavaScript APIs that exist are add, addRange, insert, remove, removeAt, and clear. The Microsoft AJAX library provides methods named like these as static methods on the Array type. So you have the corresponding APIs on Sys.Observer.

var a = [1, 2, 3]; // POJA
Sys.Observer.add(a, 4);
Sys.Observer.addRange(a, [5, 6]);
Sys.Observer.insert(a, 0, 0);
Sys.Observer.remove(a, 6);
Sys.Observer.removeAt(a, 0); // now [1,2,3,4,5]
Sys.Observer.clear(a);

It's kind of interesting what this support means. I have seen some complaints in the past that the Microsoft AJAX library does not have any "collection" classes. The reason those complaining wanted a collection class was because, well, they wanted to be able to 'observe' the array, even if they didn't realize it. Sys.Observer provides this capability, without the unnecessary bloat of an actual "collection" class that would then only be useful if every component you wanted to use with it knew about it. Since this array is still just an array, it is compatible existing code.

Observing the changes on an array is a little more interesting than on objects. When you add or remove items, you might want to know what index they are on or were on. And in the case of removal, you may want to know what the item was. All of this is available through the new Sys.NotifyCollectionChangeEventArgs class that is passed into the "collection change" event.

function onChanged(a, args) {
    // args is Sys.NotifyCollectionChangedEventArgs();
    var i, j, changes = args.get_changes();
    for (i = 0; i < changes.length; i++) {
        var change = changes[i];
        switch (change.action) {
            case Sys.NotifyCollectionChangedAction.add:
                for (j = 0; j < change.newItems.length; j++) {
                    alert("Added '" + change.newItems[j].name + "' at index " + change.newStartingIndex + j);
                }
                break;
            case Sys.NotifyCollectionChangedAction.remove:
                for (j = 0; j < change.oldItems.length; j++) {
                    alert("Removed '" + change.oldItems[j].name + "' at index " + change.oldStartingIndex + j);
                }
                break;
            case Sys.NotifyCollectionChangedAction.reset:
                alert("Array was cleared.");
                break;
        }
    }
}
 
var widgets = [
    { name: "widget1" },
    { name: "widget2" },
    { name: "widget3"}];
 
Sys.Observer.addCollectionChanged(widgets, onChanged);
 
Sys.Observer.add(widgets, { name: "widget4" });
Sys.Observer.addRange(widgets, [{ name: "widget5" }, { name: "widget6"}]);
Sys.Observer.insert(widgets, 0, { name: "widget0" });
Sys.Observer.remove(widgets, widgets[1]);
Sys.Observer.removeAt(widgets, 0);
Sys.Observer.clear(widgets);

So there you go -- all the information you could possibly need to know about what is happening to the array. Of course, just like turning POJOs into MOJOs, you can optionally turn POJAs into... uhh, MOJAs? I should point out that in addition to the change operations becoming available right on the object/array, so too do the add and remove event handler methods:

var widgets = Sys.Observer.observe(
    [   { name: "widget1" },
        { name: "widget2" },
        { name: "widget3" }
    ]);
 
widgets.add_collectionChanged(onChanged);
 
widgets.add({ name: "widget4" });
widgets.addRange([{ name: "widget5" }, { name: "widget6"}]);
widgets.insert(0, { name: "widget0" });
widgets.remove(widgets[1]);
widgets.removeAt(0);
widgets.clear();

Only, notice the difference in the name. It is "add_collectionChanged", which follows the traditional Microsoft AJAX library event pattern with an "adder" and a "remover". This time, with the "_" since it now follows the correct signature and can be thought of as an actual event on the object rather than a helper method for adding an event to a different object, like the static Sys.Observer.addCollectionChanged() method does.

But wait, there's more!

You may have noticed in the onChanged handler that each change operation can have a list of operations. And, each operation can have a list of "new" or "old" items. The reason for the "new" or "old" items is because of the batch operations you can do in one shot, like addRange(). When you use addRange, there is a single change operation with the new items in the newItems field, for example. But still, that is a single change operation, so why the list of change operations?

Say you have a few different operations you need to perform. You need to remove one item and then add two items. Obviously you must remove the item and then add the new item -- there's no operation that will do both of these steps at once. Any observers of the array are going to be notified of each operation separately, one after the other. If those observers are doing something expensive with that knowledge, you could have a flickering problem. Perhaps the observer renders out the list of items, refreshing the view each time the array is modified. There would be no point in refreshing when you remove an item, only to have to refresh again when you add one right afterwards.

Declaring the beginning and end of an operation

Well, this is a pattern that is actually already employed by the Microsoft AJAX library. When you need to tell a component to hold off on actually doing anything with the changes being made to it, you first call beginUpdate() on it. When you are done, you call endUpdate(), at which point all the changes you made in the meantime are processed at once. The base Sys.UI.Component class provides these beginUpdate and endUpdate methods, but of course, it is up to the implementation of the component to actually honor this behavior. Sys.Observer is not a component, but provides the methods as well, and honors your wishes. Observers are not notified until you call endUpdate().

Sys.Observer.beginUpdate(widgets); // hold your horses man
Sys.Observer.add(widgets, { name: "widget4" });
Sys.Observer.addRange(widgets, [{ name: "widget5" }, { name: "widget6"}]);
Sys.Observer.insert(widgets, 0, { name: "widget0" });
Sys.Observer.remove(widgets, widgets[1]);
Sys.Observer.removeAt(widgets, 0);
Sys.Observer.clear(widgets);
Sys.Observer.endUpdate(widgets); // ok I'm done!
// all operations passed to onChange at once here

The same thing applies to POJOs -- the propertyChanged event is held off until you call endUpdate().

What about Foo.Bar?

Even POJOs can be more complex than what I've been talking about so far. You might have nested POJOs, where the field of a POJO contains another POJO -- a "sub property", if you will. For example, here is a contact POJO.

var contact = { name: "Dave Reed",
    address: { street: "1 Microsoft Way",
        city: "Redmond",
        state: "WA",
        building: 41
    }
};
contact.address.building = 42;

Building 41 is wrong -- gotta change that to 42! But no one will know I've done that. Even if someone is observing the contact object, how will they know the address field has been updated? No problem -- just set the value using the supported "dotted" syntax.

var contact = { name: "Dave Reed",
address:street: "1 Microsoft Way",
            city: "Redmond",
            state: "WA",
            building: 41 }
};
Sys.Observer.addPropertyChanged(contact, contactChanged);
function contactChanged(contact, args) {
    if (args.get_propertyName() === "address") {
        alert(contact.address.building);
    }
}
Sys.Observer.setValue(contact, "address.building", 42);

Even though the address field of the contact has not itself changed, a value on it has. That qualifies as a property change for the address field, so it shows up as a change to the address, not to the 'building' field. That's important, because if I want to observe changes to the contact object as a whole, I wouldn't always know that a field on contact may have sub-fields. It wouldn't be nice to have to observe changes to address directly, too. If I want specific information on what fields of the address changed, well then I can observe that directly instead.

Not just for Objects and Arrays

You can use these APIs on more than just objects or arrays. You can use it on DOM Elements, or on AJAX controls, components, and behaviors. Any AJAX class, or even components from other libraries. You can even use it on the global "window" object, which means you could use it to monitor changes to global variables. You could combine the observation of arrays and objects, for example, to be notified of any changes to an array OR any of the objects it contains. The caveat of course is that you must use Sys.Observer's APIs to change the value rather than doing it directly.

Remember our discussion of JSON web services returning plain data, and you having to wrap that data or convert it to get this functionality? Well here you go -- and one of the great things about the approach this technique uses is that you don't have to pay the cost for wrapping or converting objects that you don't actually need to 'observe'. If you don't observe an object, and you don't change its value, there is 0 cost. If all you do is change its value with setValue(), but no one is listening, the overhead of checking for any registered observers is very tiny.

All of this has been a pretty hypothetical discussion, with no real concrete examples of how you might use this feature. Well, I'll put together some examples if the interest is there. But a good place to start is to take a look at the Microsoft AJAX 4.0 Preview 3 Live Bindings feature, and realize that it is the flux capacitor, err, I mean, this functionality that makes that feature possible. A great place to get an idea of what live bindings has to offer is this excellent example.

Happy Coding!

Plenty of people have already seen this... interesting... error screen in chrome.

image

I wanted to see what a run-away script would do to Chrome. There's always a warning that the script is taking too long, giving you a chance to shut it down. Here's what Chrome does...

image

What is that icon? Is the page COLD or something? It's snowing! It's wearing a scarf! I guess the connection is that the page is "frozen."

EDIT: If I decide to "kill" it, they should have an animation of a spear going through it or something. Is it even acceptable to say you can "kill" the page? :)

Aw, snap!

Lately I've been using a laptop more often than a desktop to work in Visual Studio, and of course like most laptop keyboards, the keys are jammed close together. The most annoying thing I keep doing by mistake is hitting F1 instead of Escape, which of course begins the not-so-quick process of bringing up help. Every time I do it, I sigh, wait, and close it.

No longer... realizing I can just disable F1 has made my day.

F1HelpBefore

F1HelpAfter

Now I can hit escape without fear.

Sky Lynn Reed's 0th birthday is 5/15/2008 at 5:44pm, when she weighed 8 pounds, 0 ounces. A nice round binary number. Our first born! There are simply no words to describe the experience. We debated on whether we should have kids for a long time. After being married almost 5 years now, we finally decided to take the plunge. Now that she's here, and about 5 weeks old, we couldn't imagine our lives without her.

SkyLynnReed

Of course, being a programmer daddy should be fun. We'll just see how early it is possible to learn to type. Imagine having an email address that you've had since before you were born? Oh, and a birthday cake with a number 0 candle on it makes sense to me. You're how old? Yeah, but you've only had that many traditional "birthdays". You've been robbed of the most important birthday there is -- your BIRTH day. As soon as she fits into it, I'll post a picture of her wearing her "Microsoft Future Developer" outfit. Dad is a geek, Sky, you better get used to it.

I look forward to just about everything that is to come. Of course it will be difficult. There will be major hurdles to jump over. Good times and bad times. But what a gift -- I get to live life all over again. I get to experience childhood as an adult.

UPDATE 

This issue is officially fixed in .NET 3.5 SP1. If you have applied the workaround in this blog post, you no longer need it. But the story of this bug is still rather interesting. 

UPDATE

If you upgrade from Microsoft ASP.NET AJAX Extensions 1.0 to 3.5, and you have a TabContainer inside an update panel, like this:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
 
        <act:TabContainer runat="server">
            <act:TabPanel runat="server">
                <HeaderTemplate>
                    Tab
                </HeaderTemplate>
                <ContentTemplate>
                    Tab Content
                </ContentTemplate>
            </act:TabPanel>
        </act:TabContainer>
 
    </ContentTemplate>
</asp:UpdatePanel>    

...you may notice a change in behavior. When the update panel updates, the UI seems to flicker off and on again, whereas with AJAX 1.0 it seemed to update instantly without any flicker. You may have noticed a similar problem with other components as well, depending on what they are doing.

This is one of those interesting bugs with a convoluted history, driven by browser quirky behavior.

The Tale -- First, some background

Update panels basically work by replacing their content with the new content from the server by setting its innerHTML. However, there may also be components defined within that HTML that register script. Those components need to be recreated now that there is a new set of HTML. UpdatePanel runs those scripts by dynamically creating a new <script> element, setting its content, and then appending the script element to the DOM. It goes something like this:

var script = document.createElement("script");
script.type = "text/javascript";
script.text = "[script that creates a new component]"
document.getElementsByName("head")[0].appendChild(script);

After it has done this for all of the components in the new content, it raises the load event on Sys.Application, among some other page request manager events.

The Browser Quirk

When you append a script element dynamically like this, would you expect the script it contains to execute immediately, or later? Keep in mind we're talking about literal script here, not a reference to another script by url. Remember once all the scripts are appended, page request manager proceeds with raising events. So whether the script executes immediately or later affects whether that component will be created and initialized before, or after those events. That's an important difference.

The intention is for the script to execute immediately. And that was a valid assumption that IE, FireFox, Opera, and Safari all agreed with at the time. That is, until FireFox 2.0.0.2 was released. With that release, FireFox started delaying the execution of the script until later. This caused components to be created after the load events, which broke some AJAX controls that depended on the ordering.

What we did about it

At the time we were in development of Microsoft AJAX Extensions 3.5. We certainly felt that this was a breaking change in FireFox that should be fixed. But we couldn't count on that. We had to fix this problem in AJAX so it wouldn't be a problem whether or not FireFox, or any browser, exhibited this quirk. The fix was to ensure the script executed first, by deferring future operations with a window.setTimeout. It goes something like this:

var script = document.createElement("script");
script.type = "text/javascript";
script.text = "..."
document.getElementsByName("head")[0].appendChild(script);
window.setTimeout(doContinue, 0);
function doContinue() {
    alert('definitely after script executes');
}

window.setTimeout is one of those poorly understood JavaScript features. JavaScript is single threaded. All setTimeout does is queue the referenced function for execution at a later time, when the timeout period has expired and there is no other javascript operation occurring (since only one train can be active at a time). Queuing the script element either executed the script, or it queued it for executing. The window.setTimeout just ensures that 'doContinue' is queued up afterwards. I often see people using this trick, but using a timeout value of "1" or something else very small. There's no reason for that, 0 does the trick, which is easily understood if you understand what it's really doing.

Problem Solved

This indeed solved the problem -- scripts would now execute in the order we intended, regardless of whether the browser executes dynamic inline script elements immediately. And so this fix was released with AJAX Extensions 3.5.

Thankfully, FireFox was also quick to respond. Likely this behavioral change broke other frameworks as well (I can only guess), so there was probably enough of a splash with it to get them to fix it in quick order -- because soon after 2.0.0.2 was released, 2.0.0.3 came out and this behavior reverted back to it's pre-2.0.0.2 behavior. But still, it was good that we had the workaround in place in case this issue ever came up again.

Problem Caused

We didn't see any adverse side effects with the setTimeout work-around, other than a small performance hit on initializing components after an asynchronous update from an update panel. Unfortunately, this turned out to affect some components much more than others. The point at which the setTimeout occurs is after the innerHTML has been replaced, but before component initialization occurs. Any component that performs any serious DOM manipulation from its initialize() method would now be doing so later than it used to. The setTimeout not only delays execution, it also gives the browser more opportunity to draw stuff on the screen. So a component that say, creates a bunch of new elements from initialize, would be causing a FOUC ("flash of uninitialized content"), since the user would first see the natural HTML of the component and then a split second later, the manipulated DOM. This is the cause of the 'flicker' you see with the TabContainer!

The Real Solution

First of all, if at all possible, AJAX components should rely as little as possible on DOM manipulation to create their initial UI. Especially if they are server components as well -- they should render out the initial UI and only manipulate it as needed. This is better practice for FOUC purposes, performance, and probably SEO or script disabled browsers too. I don't know for a fact that the TabContainer is doing this, or if it is really necessary for it to do it, I can only infer that it is based on this behavior.

The Actual Solution

Barring that, the framework should do whatever it can to improve the experience of any controls that need to rely on DOM manipulation from initialize.

Since FireFox fixed the quirk, and no other browsers have experienced it, we have decided the workaround is no longer necessary. All it is doing is hurting performance. If any browser makes this kind of change again, or if a new browser is released that exhibits this quirk, it may not be compatible with some components or applications that rely on the ordering of events (but at least it won't flicker). But the number of components and applications that would have a problem should be very small, and such a quirk we hope would be deemed incorrect behavior and fixed in that browser. It may not be specifically called out in any W3C recommendations (provide me a link if you find one), but it should be, and the fact that the 4 major browsers of today are consistent with this really says something about what the correct behavior is. So all in all, the workaround just it isn't worth the cost anymore.

So the workaround is removed in the upcoming 3.5 Extensions release. But if you want to apply the fix to your 3.5 scripts today without waiting, here is how to do it. The goal is to replace the internal method used by PageRequestManager to load scripts, in the ScriptLoader component. The easiest/simplest way to do it would be to put this script in your own JS file, and then reference it on every AJAX page with the ScriptManager. There other ways of patching it, such as by extracting the AJAX scripts and using the ScriptManager.ScriptPath or ScriptReference.Path feature to point to your modified copy of MicrosoftAjax.js and MicrosoftAjax.debug.js (copies of which are in your program files directory).

Sys._ScriptLoader.getInstance()._loadScriptsInternal = function() {
    if (this._scriptsToLoad && this._scriptsToLoad.length > 0) {
        var nextScript = Array.dequeue(this._scriptsToLoad);
        var scriptElement = this._createScriptElement(nextScript);
 
        if (scriptElement.text && Sys.Browser.agent === Sys.Browser.Safari) {
            scriptElement.innerHTML = scriptElement.text;
            delete scriptElement.text;
        }            
 
        if (typeof(nextScript.src) === "string") {
            this._currentTask = new Sys._ScriptLoaderTask(scriptElement, this._scriptLoadedDelegate);
            this._currentTask.execute();
        }
        else {
            document.getElementsByTagName('head')[0].appendChild(scriptElement);
            Sys._ScriptLoader._clearScript(scriptElement);
            this._loadScriptsInternal();
        }
    }
    else {
        var callback = this._allScriptsLoadedCallback;
        this._stopLoading();
        if(callback) {
            callback(this);
        }
    }

Include this script on your page with a TabContainer, and volia, the flickering will be gone.

This has been a bug tale! Happy coding, I wish you all a non-flickering UI.

UPDATE 05/02/08: Removed the bit about 3.5 extensions preview. The fix isn't in the extensions preview as I originally thought.

More Posts Next page »