Making the Wijmo Drop Down Listen

Wijmo is a awesome HTML/JavaScript toolkit that provides styled widgets for any website or web application. They provide great integration with the equally brilliant KnockoutJs.

I was using the Wijmo drop down control, but I found that there was something a bit strange: the control does not update it’s value when the observable changes its value. The control is actually a very thin wrapper for Knockout’s default binding for the <select> element. Knockout listens to the element’s updates and can update the element from the observable, but Wijmo does neither: it only can update the HTML that control is bound to. Thus, the value on the control is never updated at all; the observable’s value is updated because the widget updates the HTML and then Knockout updates the observable as it listens to the HTML.

This posed a problem as I would have to manually listen to the observable and then update the widget, this is boring and I should not have to do it. So I wrote a wrapper for it and extended the wijdropdown binding:

(function () {
    // override the wijdropdown to update the drop down display label when the selection changes
    var proxied = ko.bindingHandlers.wijdropdown.init;
    ko.bindingHandlers.wijdropdown.init = 
        function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

        var options = allBindingsAccessor();
        var value = options.value;

        // subscribe to the changes and update
        if (ko.isObservable(value)) {
            value.subscribe(function () {
                $(element).wijdropdown("refresh");
            });
        }

        // continue as normal
        return proxied.apply(this, arguments);
    };
})();

The original code would have required me to listen to each observable with this code:

myObservable.subscribe(function () {
    $("#selectElement").wijdropdown("refresh");
});

But the extension does away with this and I can simply bind to the element:

<select data-bind="value: pageSize, wijdropdown: {}">

The reason that there is a “double” binding is that the default Knockout binding is sufficient to work the drop down, and the wijdropdown just adds the styling.

JavaScript Ajax & ASP.NET WebAPI

Recently I was working on a HTML/JavaScript web application and I was having one of those moments where everything was working fine except for one small thing: the server always seemed to receive NULL.

I tried the usual check-for-null-before-sending, but this was not the problem. Maybe it was breaking in the jQuery Ajax call? Is that even possible? 🙂 Everything was perfect, including when checking the request data with Internet Explorer’s Network Traffic Capturing Developer Tool. It was sending the data across. The JSON was valid and everything.

I decided it was the server. It was a basic ASP.NET WebAPI. All the GETs were working so why was the POST failing? I checked the ApiController’s http context request content. That was correct. The only thing that was wrong was the method’s object parameter value being NULL.

So what was it? The client was sending the right data and the server was receiving it, but the object was NULL.

Here is the JavaScript code:

$.ajax({
    url: '/api/ingredient',
    type: 'POST',
    data: JSON.stringify(ingredient),
    contentType: 'json',
    success: function() { ... },
    error: function() { ... }
});

That was perfect. Now on the server:

public class IngredientController : ApiController
{
    public void Post(IngredientDto ingredient)
    {
        // it failed here as &quot;ingredient&quot; was NULL
    }
}

After searching for some time and trying all sorts of things, I finally found where I went wrong. Now, we all know Microsoft for not being very standards compliant, I mean look at Internet Explorer before version 9, it was pretty glum times. But the problem lay with Microsoft being too standards compliant. The problem lay in the small string, “json”: it is not the right string. Of course if this was a strongly typed language, an enum based action, this would have never have happened. (Look out for my upcoming post on Type Safety)

The informal standard according to Internet Assigned Numbers Authority‘s (IANA) media types and The Internet Engineering Task Force‘s (IETF) RFC4627:

The official MIME type for JSON text is “application/json”.

Wow. What a waste of time. And of course, as soon as I changed the Ajax type from “json” to “application/json” everything JustWorked™.
So the new code is:

$.ajax({
    url: '/api/ingredient',
    type: 'POST',
    data: JSON.stringify(ingredient),
    contentType: 'application/json',
    success: function() { ... },
    error: function() { ... }
});

I hope this helps someone to avoid what I was doing: wasting time. But I did learn a few other things along the way, all was not lost.

Pre-Loading Silverlight Prism Modules & Assemblies

I was developing a Unity/Prism Silverlight enterprise application which used many shared assemblies and several modules. I wanted to show a ‘startup progress’ for the core assemblies so the application would have a better user experience, especially for the users’ first few moments of the application.

Problem

The Silverlight plugin downloader only reported the progress for the shell. User experience was very poor due to the lack of a real gauge of the total progress. Even though the entire application was about 7 MB, the shell was only 500 KB. This resulted in the built-in progress bar reaching 100% very quickly, way before the actual download had reached 10%. This was not really a problem on faster connections, but on slower connections, there was a long delay before the application really started. This delay exists because the shell is finished downloading, but Silverlight is still downloading all the other assemblies and modules. These other assemblies make up the main part of the application, and thus is more important compared to the shell.

So what I wanted to do was to find some way to hook into the actual Silverlight download requests of all the files and then use this instead of the built-in progress reporting. However there doesn’t seem to be any way to do this from JavaScript.

Solution

I know that almost all browsers support caching and subsequent loads from the cache are almost instantaneous. I can use this to my advantage. So what I did was to pre-download the files that would have been downloaded if I was using the built-in downloader. Then, when the Silverlight control started its own download, all the required files would be in the browser cache. This allows the application to no longer need to download the files, and the application startup would be very quick, thus not needing a Silverlight progress section here.

Implementation

This solution calls for several things:

  • I don’t want any hardcoded values, such as sizes, filenames or urls.
  • The splash screen should be seamless with the actual Silverlight application
  • JavaScript downloader should start and then switch to the Silverlight control once it is finished.

The first thing that I needed to do on the server was to create a way for my JavaScript code to get a list of all the files and their sizes that it needed to download. Just to keep things simple, I created a simple ASP.NET Generic Handler that returned a JSON string of all the files. Because Silverlight downloads the files in our “ClientBin” folder, my handler simply enumerates the files in this directory and returns this. I also didn’t want to build up this resulting string manually, so I used a DataContractJsonSerializer that serializes the array of files – I created the returning types as internal classes of the handler.

On the client, I can request the list then calculate the total size for the progress and start downloading. As each file finishes downloading, I can update the progress message and it will be more accurate to what is really happening.

The splash screen is a very simple HTML div that is displayed over the actual Silverlight object. The Silverlight object is actually hidden by default using CSS styles, to prevent it from automatically starting up. When my JavaScript reports that all the files are downloaded, I hide the splash screen div and show the Silverlight control. This provides a very accurate, user-friendly way of reporting progress. And when the download reaches 100%, all the required files are all finished and on the client.

Notes / Observations

I did have a problem when I pre-downloaded the shell xap file: Silverlight did not start the actual application. So to work around this I decided to downloadd all the files, except the shell and let Silverlight do this one. Now this caused slight problems in my download mechanism: First the progress would be off slightly and I would have no way of reporting this shell progress. Silverlight has JavaScript callbacks for the shell downloads: the onSourceDownloadProgressChanged function.

Because I know the size of the shell – from my handler, and I would have notifications from Silverlight about this file’s progress, I could then combine this with my progress message to get a nice value. So effectively, my download stops at 90% and then the Silverlight control will take over and notify me of the shell’s progress which I work out how far it should really be.

Currently I am using both the HTML element and the Silverlight mechanism for splash screens. For the first bit, I use the HTML element and when the Silverlight takes over, I hide it and the Silverlight (xaml) version shows. Both are exactly the same so the user does not notice the switch at all.

Code

This is the server-side handler. The Browser Cache mechanism for the urls are case sensitive, so remember to use the case that Silverlight is going to use for it’s requests.

public class BrandDirectorFilesHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";


        var serializer = new DataContractJsonSerializer(
            typeof(DownloadableFileResponse));
        serializer.WriteObject(
            context.Response.OutputStream, 
            GetFilesInRoot());
    }

    private static DownloadableFileResponse GetFilesRoot()
    {
        // logic to read the file list from the file system
    }
}

Here is the resulting objects that I serialize for the client.

[DataContract]
internal class DownloadableFileResponse
{
    [DataMember]
    internal IList<DownloadableFile> Files { get; set; }

    [DataMember]
    internal long TotalSize { get; set; }
}

[DataContract]
internal class DownloadableFile
{
    [DataMember]
    internal string Url { get; set; }

    [DataMember]
    internal long Size { get; set; }
}

This is the part of the whole system that controls the downloads of the files from the client side.

var totalSize = 0;
var progress = 0;
var xapFile = null;

// Silverlight default functions
function onSourceDownloadProgressChanged(sender, eventArgs) {
    if (xapFile === null) {
        // there may have been a problem obtaing the file list
        // so create a dummy state for the silverlight to take 
        // over from - these values are just the last known 
        // values from a previous run that I did
        totalSize = 7000000;
        progress = totalSize * 0.88;
        xapFile = {
            Size: 700000
        };
    }

    var shellProgress = progress + (eventArgs.progress * xapFile.Size);
    var shellPercent = shellProgress / totalSize;
    var text = Math.round(shellPercent * 100).toString();

    // this bit is for the actual Silverlight splash.xaml
    sender.findName("ProgressText").Text = text;
    // this is the html element
    $("#ProgressText").text(text);
    // I do both just to be sure
}

// the javascript for pre-caching the assemblies
$(function () {
    // get this apps root
    var urlParts = location.href.split('?');
    var mainUrl = urlParts[0];
    mainUrl = mainUrl.substring(0, mainUrl.lastIndexOf('/'));

    // download the list of files from the handler
    $.ajax({
        url: mainUrl + '/BrandDirectorFilesHandler.ashx',
        success: function (data) {
            var response = $.parseJSON(data);

            // set the total size for the silverlight bit
            totalSize = response.TotalSize;

            // don't download the shell xap file
            // get the xap filename from the Silverlight DOM element
            var shellXapPath =  
                $("#silverlightControl")
                .children()
                .filter(function (index, child) {
                    return child.name === "source"; 
                })[0].value;
            // find the shel in the list from our server
            xapFile =
                response.Files
                .filter(function (item) {
                    return shellXapPath.indexOf(item.Url) !== -1;
                })[0];

            // start downloads
            $(response.Files).each(downloadFile);
        },
        error: function () {
            // default to silverlight on any errors getting the list
            onAllDownloadsComplete();
        }
    });
});

// all downloads are complete, show the silverlight control
function onAllDownloadsComplete() {
    $("#silverlightControlHost").show();
    $("#htmlLoading").hide();
};

// initiate the download for each file
function downloadFile(index, file) {
    if (file !== xapFile) {
        $.ajax({
            url: new String(file.Url).toString(),
            complete: function () {
                // download of the file complete we can ignore 
                // errors, as Silverlight can deal with it
                progress += file.Size;
                var progress = Math.round(progress * 100 / totalSize);
                $("#ProgressText").text(progress.toString());

                if (progress >= totalSize - xapFile.Size) {
                    onAllDownloadsComplete();
                }
            }
        });
    }
}