RSS

Tag Archives: WebSockets

Long Poll Sally – ASP.NET MVC AsyncController

Just like the rest of us, I use polling occasionally. When I learned of WebSockets, I came across my reading about a term I wasn’t acquainted with: Long Polling (or “Comet“). It can be viewed schematically here. To put it simply, while polling can be explained as a series or recurring requests to the server for updates, Long Polling is more or less the same, only technically, the client opens a request to the server, but the server doesn’t return an immediate response and keeps the connection open. When the server has a response, it will use that open connection to notify the client. The client then has to perform another request to reopen a connection for the next update.

At first, when I realized what Long Polling is, I didn’t like the idea much. I mean, if you end up reopening a request to the server like regular polling, why bother? This comes in handy only for less-frequent notifications from the server side, otherwise its just like Polling. Besides, with the new WebSockets in place – who needs it? But then I did some more reading and decided that it might come in handy after all. The main problem I see for using WebSockets is IE9. The major browsers (Chrome, Firefox and the soon to be released IE10) support WebSockets. Cool. But IE9 does not support it. “Fine” you say, have your users upgrade their browsers to IE10. Ahhhh, but MS has decided to limit IE10 to Windows 7 or above. MS is taking several steps to force us to upgrade to their latest releases: No IE10 for Vista, just like WebSockets isn’t planned for IIS7. Funny enough, Google’s Chrome supports XP and Firefox is also compatible with older Windows (in fact, a short visit to Wikipedia reveals that: “Windows XP SP2, XP SP3 and above is now the minimum requirement for Firefox 13.0 and above”…) I find it quite amazing, that MS’ latest browsers cannot be installed on their own operating systems, while their biggest competitors can. It’s as if Microsoft believes that users will upgrade to their latest operating systems just to get their better browser, when they have major competition which is compatible with legacy Windows. Gregg Keizer rightfully points to an anonymous comment on IE’s blog: “IE9 is the new IE6.” Microsoft is working so hard on renewing IE and kicking out IE6, but it performs such a strategic mistake by leaving IE8 and IE9 for a long long time.

Anyway, that’s a major issue as far as I’m concerned. IE6 to IE9 will probably remain with us for quite sometime, as many users still use Windows XP or Vista. All of these users will not enjoy WebSockets support, and we developers will have to continue to develop alternatives to MS’ browser policy of not allowing their own users to upgrade. I guess that this more or less explains why Polling and Long Polling are still relevant: we simply can’t rely on WebSockets alone in the upcoming years.

“Hello World”

Following several blog posts, especially this one by Clay Lenhart, I ended up with the following “Hello World”-like example. Here is the client. It’s fairly simple and self explanatory:

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Simple</title>
</head>
<body>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
            openConnection();
        });

        function openConnection() {
            $.post("@Url.Action("Simple", "MyAsync")", function (results) {
                if (results.Data) {
                    $('#log').text(results.Data);
                }

                openConnection();
            });
        }
    </script>
    <div id='log'>
    </div>
</body>
</html>

Here is the server side (explanation below):

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public void SimpleAsync()
        {
            AsyncManager.OutstandingOperations.Increment();

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(TimeSpan.FromSeconds(10));
                AsyncManager.Parameters["contents"] = DateTime.Now.TimeOfDay.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });
        }

        public JsonResult SimpleCompleted(string contents)
        {
            return Json(new { Data = contents });
        }
    }
}

The server code works similarly to the Web Services Async pattern: There is a ‘Begin’ (SimpleAsync), and an ‘End’ (SimpleCompleted). Here is what we see here:

  • Line 8: A would-be async controller must derive from AsyncController. This is what gives us the AsyncManager property through which we accomplish async behavior in MVC.
  • Line 10 is where the async begins. Note, that while the client called the “Simple” Action, our method is called SimpleAsync. In Line 22 you will find it’s counterpart callback method which will be called upon completion (“complete” callback).
  • Lines 12 & 18 are completing operations: In line 12 you announce how many “outstanding operations” you have, which is simply a counter you set at the start of the async operation. When the async operation ends you decrement this counter. When the counter reaches zero, the “completed” callback is called and the response returns to the client. This resembles a C++ reference counter for a smart pointer.
  • Lines 14-19 simulate an async task call. This is where you call time consuming logic, or where you register to receive notifications for two-way communication, simulating WebSockets behavior.
  • Line 17 is how you may pass arguments to the “completed” callback (Line 22).

Here’s a screenshot from IE9 running as IE8:

  1. Response from the server.
  2. Interval of the 10 second requests.
  3. Current pending request.
  4. Browser running in IE8 mode – after all, this is what this effort is all about.

There you have it – quite a simple mechanism to perform async MVC operation, which can evolve into a WebSocket-like operation (see below).

Multiple “outstanding operations”

The OutstandingOperations property which returns an OperationCounter class which is a sort of a reference counter for “pending async operations”. This means that if you have multiple async operations scheduled per a single async request, you may set the counter to the number of those operations, and have each operation decrement the counter when it completes. When the counter reaches zero, the “completed” callback will be returned. Here’s an example:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public void MultipleAsync()
        {
            AsyncManager.OutstandingOperations.Increment(3);

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
                AsyncManager.Parameters["param1"] = DateTime.Now.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(2000);
                AsyncManager.Parameters["param2"] = DateTime.Now.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3000);
                AsyncManager.Parameters["param3"] = DateTime.Now.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });
        }

        public JsonResult MultipleCompleted(string param1, string param2, string param3)
        {
            return Json(new { Data = string.Format("{0} {1} {2}", param1, param2, param3) });
        }
    }
}
  • Line 12 states that there are three async pending operations to be completed before returning a response.
  • Three new threads simulate those async operations. Each completes in a Decrement being called, to signal an async operation completion (lines 18,25,32). Each also provides a different argument with the result of the pending operation, which will be passed on to the “completed” callback.
  • Line 36: the “completed” callback receives the results of the pending operations and returns a response.

WebSocket-like implementation

UPDATE: Before you dig into this code, you might be interested in SignalR. Turns out that this is a broadcasting solution from guys at MS. It supposed to auto-detect and use WebSockets, Long Polling or whichever technology is available on the client. I have not tried this yet, but it looks very promising. You can see Scott Guthrie talk about this here (1:09:38).

Now it comes down to the “main event”: Implementing a WebSocket like implementation. Instead of opening a WebSocket from the browser to the server for two-way communication, the idea is to open a request which the server will maintain asynchronously but not so much for the purpose of supporting a lengthy operation, as much as to maintain the connection for a future response from some business logic component. Here’s an example for accomplishing this. First, the publisher (i.e. class which publishes business logic events to subscribers):

using System;
using System.Timers;

namespace LongPolling.Controllers
{
    public static class MyPublisher
    {
        public class MyEventArgs : EventArgs
        {
            public string Contents { get; set; }
        }

        public static event EventHandler<MyEventArgs> Notify;

        private static Timer timer;
        static MyPublisher()
        {
            timer = new Timer();
            timer.Interval = 10000;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.AutoReset = false;
            timer.Start();
        }

        static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                timer.Stop();

                if (Notify != null)
                {
                    Notify(null, new MyEventArgs { Contents = DateTime.Now.ToString() });
                }
            }
            finally
            {
                timer.Start();
            }
        }
    }
}

Not much here to tell. The MyPublisher class simulates receiving notifications from the business logic using a simple timer, that every 10 seconds publishes to subscribers the current DateTime. Next comes the AsyncController:

using System;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public void LogicAsync()
        {
            AsyncManager.OutstandingOperations.Increment();

            MyPublisher.Notify += MyPublisher_Notify;
        }

        private void MyPublisher_Notify(object sender, MyPublisher.MyEventArgs e)
        {
            MyPublisher.Notify -= MyPublisher_Notify;
            AsyncManager.Parameters["contents"] = e.Contents;
            AsyncManager.OutstandingOperations.Decrement();
        }

        public JsonResult LogicCompleted(string contents)
        {
            return Json(new { Data = contents });
        }
    }
}
  • Line 12: Register to receive an event from the business logic class (“MyPublisher”). MyPublisher will raise an event each time it attempts to notify whatever message to registered clients.
  • Line 15 is the event handler which is raised by MyPublisher. Here we set the argument to be passed to the “completed” callback and decrement the Outstanding Operations reference counter.
  • Line 17 is probably the most important here as it’s the easiest part to forget: we have to release the event handler from MyPublisher, or MyPublisher will keep a reference to our AsyncController instance and it will never be Garbage Collected. In other words: a managed code memory leak. This is just like in Winforms: a form registers with a business class to receive events in order to display a progress bar or some other UI feedback. When you are done you call a Close( ) on that form. You mistakenly believe that because you called Close and don’t see the form anymore – it is disposed of and eligible for Garbage Collection: not remotely. The business class maintains a reference to the form instance and it is not removed at all. After a while, you begin to witness your memory growing more and more although you’re certain that you have cleaned up everything, and you end-up “windebugging” with SOS to detect that leak. In the screenshot below you can see how the event’s invocation list gets populated with just several requests from the same client browser. The event handlers are never released, which cause the MyAsyncController instances generated per request to remain in memory. By issuing a ‘-=’ we unregister correctly from the event, and the invocation list is kept clean.

Regardless of the potential memory leak described above, the major difference in this implementation from the previous sample is conceptual, and not necessarily technological: In the previous sample, the async method was used to start an async operation, which actually opened new threads. When the threads complete, each decrements the reference counter thus signaling the end of the lengthy async operation. The entire process was started as a browser initiative and simply freed ASP.NET’s threads for the time of the lengthy operation. However, in the current example, the browser opened a request for no particular operation but in order to wait for a callback from the server. The server on an entirely different logical class (“MyPublisher”) will decide when and what to return to the client. A server may return different operations, such as “display notification” about a new email, or “redirect to another page” and so forth.

Timeout

Moving on to implementing a WebSocket like behavior, one issue that was bothering is the Timout. It’s one thing to use an async server operation which is due in a reasonable time; it’s another thing when you attempt to implement a WebSocket-like behavior that may time-out due to less-frequent updates. For example, if you would like to implement a chat, updates might be frequent, but if you implement a mechanism which is most of the time idle, and just prompts notifications every now and then to the end user, we could be discussing here relatively long interval updates. Consider Gmail. When you are positioned on an email correspondence, if suddenly you receive an email related to that correspondence – a notification appears informing you that there’s a new message and you may click on “show” or “hide” to proceed. This is a good example for when a website may be open for a lengthy time without any operation, but a server may “push” a message when relevant. Therefore I tried to test whether a Timeout occurs on the client or the server, by a simple Thread.Sleep() to lengthy time intervals on the server side. It seems that an AsyncController (MVC 4) defaults to 45 seconds. After that, the client is expected to receive the following timeout exception:

“System.TimeoutException: The operation has timed out.”

I have no idea why, but settings the Timeout property seems to be completely ignored. For example, setting the Timeout to “infinite” (Timeout.Infinite) or to a simple 60000 ms (and extending the server’s Sleep to a much lengthier operation), returned a Timeout exception after 45 seconds. Luckily, I read here that you could set a NoAsyncTimeoutAttribute on the async method to state that there should not be a timeout, and in fact – this actually works (viewing the Timeout property in a debug watch shows -1, which is the value of Timeout.Infinite, but it actually works.)

Now that I have server Timeout set to infinite, I tested different clients’ behavior. On Chrome and Firefox – the browsers did not timeout even when I set the server to respond after 6 hours. This was a good behavior as far what I expected. However, in IE it timed out. This was quite frustrating, because IE is the target of this Long Polling alternative in the first place. If it times out, it means that now I have to detect how long it takes before the client times out, and that I have to implement a mechanism for having the server return a response no longer than that timeout value or I’m risking losing the connection with the client. Testing this several times shows that IE times out at approx 60 minutes (see pics below).

Now comes the harder part, which is what to do when those 60 minutes time-out. Remember: the idea is to return a response to the client browser before reaching the client time-out, and have the client re-open a new connection. I thought I could use a simple Timer for this. The timer has to be set to a predefined interval (e.g. 30/45/60 minutes etc. – depends on how much risk you wish to take here…), and decrement the Outstanding Operations reference counter if it elapses. This way the server returns a response to the client, which the clients reads as “timeout”, meaning that there’s nothing to do but re-open a request.

Here’s the code:

using System;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        private System.Timers.Timer timer;

        [NoAsyncTimeout]
        public void LogicAsync()
        {
            this.timer = new System.Timers.Timer();
            this.timer.Interval = 4000;
            this.timer.AutoReset = false;
            this.timer.Elapsed += delegate
            {
                timer.Stop();
                MyPublisher.Notify -= new MyPublisher_Notify;
                AsyncManager.Parameters["contents"] = "timeout";
                AsyncManager.OutstandingOperations.Decrement();
            };

            this.timer.Start();

            AsyncManager.OutstandingOperations.Increment();

            MyPublisher.Notify += MyPublisher_Notify;
        }

        private void MyPublisher_Notify(object sender, MyPublisher.MyEventArgs e)
        {
            this.timer.Stop();
            MyPublisher.Notify -= MyPublisher_Notify;
            AsyncManager.Parameters["contents"] = e.Contents;
            AsyncManager.OutstandingOperations.Decrement();
        }

        public JsonResult LogicCompleted(string contents)
        {
            return Json(new { Data = contents });
        }
    }
}
  • Line 8 declares a Timer variable. This timer is started in the ‘Begin’ method (LogicAsync) and is set to 4 seconds (just for this example – it’s supposed to be set to a much lengthier interval but less than 60 minutes).
  • Lines 16-22: When this timer’s Elapsed event is raised, this means that the request is timing out and should be renewed, so we unregister from the publisher (we do not want to process the event handler during re-connection), and decrement the Outstanding Operations reference counter in order to immediately return a response to the browser. The browser is supposed to interpret this response as “do nothing” (NOP) and re-open a request.
  • Line 33: If the timer did not elapse but we did get an event from the Publisher, we immediately stop the timer, and execute the returning response as normal. This ensures that the timer won’t elapse till we finish implementing the response logic.

In the example above, assuming that a MyPublisher is set to return a response every 10 seconds, you are expected to see two “NOP” responses per one correct response of the handler being raised:

await/async

This here is just an extra to this post. I was thinking whether I could use the new async lib from C#. I came up with this:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public async Task<JsonResult> MyAction()
        {
            string contents = null;
            await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(TimeSpan.FromMinutes(30));
                contents = DateTime.Now.TimeOfDay.ToString();
            });

            return Json(new { Data = contents });
        }
    }
}

The code above seems to be working well but I’m somewhat uncertain whether it’s the correct implementation or best practice for using await/async in MVC.

UPDATE: In Scott Guthrie’s lecture (1:15:25), you can view async/await support which is similar to the example above.

However, when I tried to rewrite the “MyPublisher pattern” using await/async (excluding the timer part), I ended up with something I wasn’t pleased with:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public async Task<JsonResult> MyAction()
        {
            ManualResetEvent ev = new ManualResetEvent(false);
            string contents = null;
            EventHandler<MyPublisher.MyEventArgs> d = null;
            d = delegate(object sender, MyPublisher.MyEventArgs e)
            {
                MyPublisher.Notify -= d;
                contents = e.Contents;
                ev.Set();
            };

            await Task.Factory.StartNew(() =>
            {
                MyPublisher.Notify += d;
                ev.WaitOne();
            });

            return Json(new { Data = contents });
        }
    }
}

Nope, I was clearly unhappy with this code.

Summary

To be honest – I’m not thrilled at all to have to use Long Polling. I didn’t like polling either, but polling was simple – the browser makes requests at (almost) regular intervals, checks for updates. End of story. But with IE10 limited to Windows 7 and above, it seems like Long Polling is a possible solution to achieve a “less frequent polling” but still with “real-time” updates. Having said that, one needs to remember that other solutions are available such as using Flash or Silverlight for achieving two-way communications, and to be honest, I’m uncertain how Google Docs document sharing was implemented. You might also be interested in pubsubhubbub which is based on Atom/RSS feeds (at least watch their really cool “what is PubSubHubbub” video). There are other utils which provide reverse-Ajax and server-pushing such as WebSync, but I haven’t used them myself.

UPDATE: As specified above, SignalR is a .NET based solution from guys at MS which you should also probably look up.

Although the majority of my blog posts relate to stuff that I am learning and documenting as I go along, in this particular case I feel like Long Polling is a technique that I have not experienced sufficiently in order to recommend it. Although this is also true for WebSockets, WebSockets are designed to provide a two-way communication so I was feeling a lot more comfortable recommending them. I see Long Polling not as a technology on its own, but rather as a technique which is designated to provide a solution to a problem using existing technology, which isn’t specifically targeting that same problem. However, I am planning on implementing this soon in order to learn whether it proves itself as reliable and comfortable.

UPDATE: I attempted to implement a Publisher which will be able to filter out the browser that initiates updates to the rest of them using the above technique. My solution had one open Long Polling Ajax request and another Ajax request posted to the server from the same browser representing a user’s update. This was supposed to be nothing too clever: just exclude the current user from the Publisher’s event notification list. I thought of using the Session’s ID to make that distinction, when I noticed that my async requests got stuck almost immediately. At first I thought that this was related to the number of requests I had open from several browsers over a Windows 7 workstation, but slowly and painfully I discovered that this was because I inserted something into the Session in order to make the Session ID sticky. Googling revealed a reason: seems like AsyncController locks the Session in order to make it thread-safe between open requests from the same session. In order to use the Session from an AsyncController you probably have to declare it as read-only using the SessionState attribute. I have not found an “official” explanation for that yet although I’m sure that there is, and the best I found so far was this, this and this blog post. If anyone finds a more documented or official blog from MS guys about this, please comment.

Last credits

Little Richard gets the credit for this blog post’s title.

 
2 Comments

Posted by on 19/03/2012 in Software Development

 

Tags: , , , , , , , ,

HTML5 WebSockets Revolution (?)

This post is mainly combined of two parts: a somewhat philosophical approach to WebSockets, and a technical example for pushing data from the server using WebSockets. If you’re just looking for the technicals, you can click here and skip the philosophy.

Every now and then comes a technology that revolutionizes how we program. You can argue what Revolution in software development means, but I just like to think of it as something that either really changed our everyday programming (e.g. Object Oriented, LINQ, Ajax) or something that is somewhat an architectural change (e.g. SOA, Cloud programming). Microsoft has issued plenty of technologies in the past decade, many of which could have been considered as revolutionary but have either failed in competition (e.g. Silverlight), or have improved the existing but weren’t really revolutionary in concept by themselves (e.g. WCF, WPF). Don’t get me wrong – I use Silverlight for all those things that cannot be achieved using plain HTML & JavaScript, but the tables have turned in favor of HTML5, also as far as MS is concerned. But, Silverlight for the browser will probably continue to fill-in the gaps where HTML5 is still lacking in functionality or lacking implementation. For example, IE9 doesn’t implement multiple input file upload yet, and even if it did, you can’t run a code that will compress the files prior to uploading them – this is solvable using Silverlight.

Looking for the “what’s new” in .NET 4.5 got me reading about “Support for WebSockets Protocol”. When I read it I was truly shocked and amazed, as I wasn’t aware of HTML5 WebSockets at all up to that point, and here before me lay the foundations to a possible revolution in web development architecture, no less. At first, one can read about WebSockets and think that it’s just another feature among many others, but I believe that it is revolutionary in concept. It revolutionizes the concept of request/response. Unlike regular client-server non-web applications which are free to “push” messages from servers to clients, the web architecture is built of the client initiating a request and the server responding with a response. The server is basically unable to “push” messages to the client (excluding plugins which may be doing so). WebSockets allow you to do exactly that. In the MS article referenced above, their sample uses WebSockets to respond to an initiating client request. However, WebSockets could be used to perform the opposite, and upon opening a socket from the client – have the server initiate from then on and push messages to the client without having the client to initiate a request as before.

So what’s so revolutionary? I can think of two main things: 1) No more polling and 2) content can be controlled and pushed from the server without having the client initiate a request.

Polling
This will surely be a winner here. Web applications today are more and more “live”. Our clients browse to our website and receive “live” updates about events or messages. Just open up a Firebug’s Net panel in Facebook, Gmail or your favorite “real-time” stock related website and see polling in action. There are a couple of good pics that describe polling and “long polling” here. As you can easily see, polling is a periodical event which is triggered occasionally by a client “just to check” if there are updates from the server. This architecture is problematic in several ways, some of which are listed below:

  1. Polling isn’t “real time”. I believe that this isn’t really an issue for the majority of websites. After all, you can wait several seconds till you’re notified about that email that has already arrived on the server. But you might want to be notified immediately about a change in the stock market. So, if you have to have “real time” updates, you have to poll very frequently, which leads us to the next issue.
  2. If you have gazillions of users, polling may have a serious performance impact on your servers and as a result on your clients. And the more frequent the polling is, the more frustrating your clients will be.
  3. Lengthy operations: if you poll just to “keep alive” or to receive a minor update, polling may work quite smoothly. But what if your polling triggers a somewhat lengthy operation on the server? For example,  if your polling request results retrieved using a lengthy DB query, or a call to a Web Service that just happens to be down or busy? Multiply that by the number of your clients, and expect possible client timeouts or thread-short servers.

WebSockets clearly solve most of these issues. If a server maintains a list of client WebSockets, the client no-longer have to perform polling, as the server may notify them of changes. The server may either notify changes to specific clients (e.g. notify a client email application that an email has arrived to the user); or it can notify all the users (or groups of users) about a certain update. If you have gazillions of users, this update can be performed smartly, split across groups of users or different servers according to a certain logic which fits the nature of your application.

Program Flow
This is where the revolution can really occur, or die…. I’ll use ASP.NET WebForms and MVC as an example to this. The difference between WebForms and MVC is not so much in technology, as in concept. The general idea behind MVC is that requests arrive at a certain Controller, which retrieves a Model and decides which View should be displayed to the user, whereas in WebForms the request usually starts and ends at a referenced Page and rarely redirects the client to a different page (you can also use Server.Transfer, but this has it’s own challenges). So, in MVC, a Controller is responsible for deciding what to do, right? OK, so, this may be used as a concept with WebSockets too. Imagine a client application that loads an html page with the basic required layout, that registers a WebSocket with a server. Then imagine a Controller-like class on the server which decides what the user should see next, and pushes that to the client browser. Similar to MVC, a Controller class decides what the user should read next, but unlike MVC, that Controller class pushes the content to the client, without having the client request for it. The server has the initiative. Now, you may argue if this is desired, but this really depends on your web application. The web today is mostly interactive – the user has to request information and then the server responds. But think of how T.V. works (that is, non-interactive T.V.) – content is constantly pushed from the server onto the client. This includes media, commercials, real-time tickers etc. While interactivity is important to our users, some users don’t even know about stuff that exists in our website in the first place, so they don’t even know to request that content. How many times have you learned of something you were sorry that you didn’t know about sooner? How many times did you open your favorite news website and was disappointed that there was nothing new and you started to actively look for something new to read? You had to request for that information and look for it, instead of having smart servers push that information to you.

Example: You program a web application that focuses on entertainment, news or social networking. These usually thrive on “live” events: “just let us notify you of something that just happened, so you won’t leave our website.” This doesn’t have to end with polling for the latest news and displaying it in a ticker; You can change the entire html layout of the page according to the content you wish to display. A sports website can notify the client that an anticipated game you have registered to see is starting (“Let’s take you live to the game”); an entertainment website can notify a client when a show starts, or when the Oscar is being given to the Best Movie; A social network can push messages, events, pics and more; Forums can update their threads live. Another example would be “live profile-specific” commercials. You can “push” commercials to your clients upon certain events and profiles. Yet another example I can think of is that your website may offer assistance to your users based on their exposure level to certain features or content that they were never (or hardly ever) exposed to. I don’t know if these given examples convince you of the possible revolution here, but I’m sure that more examples can be thought of. The point is, that the web has a chance to become more content and logic driven and less request-based, where required. Even if the examples above can all be resolved using polling, I’m referring more to the architectural change that can be made due to the technology.

IIS

OK – this is a really frustrating thing now. Turns out that MS is currently supporting WebSockets only in IIS 8. When I read about WebSockets in ASP.NET 4.5, I downloaded Visual Studio 11 Developer Preview and installed it, only to find out that IIS 7 does not support it, and is not going to in the future according to this. I guess that MS is strategically not releasing new technologies for older O/S platforms in order to force us to update to their latest O/S. The same goes for .NET 4.5; as you can understand from the System Requirements of the Developer Preview, .NET 4.5 has a minimum request of Windows 7 (that’s right, not even Windows Vista). I believe that this really cripples us ASP.NET developers from taking advantage of WebSockets soon. Many of the web applications still use Windows 2003 with IIS6. It will be a real shame that browsers will support WebSockets a lot sooner than we can actually employ them, unless an open source alternative plugin will come up or MS comes to their senses.

So, I had to download and install Windows 8 Developer Preview, and install it on a VirtualBox (read here if you have to have custom resolutions to fit your screen). After that, I had to install VS11 Developer Preview because the VS11 that comes with the Windows 8 Developer Preview with development tools is a VS Express version that doesn’t support ASP.NET – and I wanted to debug stuff and not only run it. Finally, I had to install IIS with the WebSockets support:

After that, I was able to test WebSockets.

“Push, push!”

The first thing that I did was to try out MS’ WebSockets sample. This was working as expected, and sending content from the client using a WebSocket resulted in the server sending back that content.

Based on the MS sample, I proceeded with testing the theory described earlier, and maintain a list of WebSockets in order to push data from the server willingly (demonstrated by a simple timer which every 10 seconds transmitted the time-stamp from the server). Yes! it worked. And there was much rejoicing.

Here’s the screenshot (note, that neither Firebug nor IE10 Developer Tools fail to notify at this time that such interactivity took place):

Here’s the client code:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <script type="text/javascript">
        var socket;
        if (typeof(WebSocket) !== 'undefined') {
            socket = new WebSocket("ws://localhost/WebSockets/MyDispatcher.ashx");
        } else {
            socket = new MozWebSocket("ws://localhost/WebSockets/MyDispatcher.ashx");
        }

        // Receive a string message from the server.
        socket.onmessage = function (msg) {
            document.getElementById("serverData").innerHTML = msg.data;
        };
</script>
    <form id="form1" runat="server">
    <div id='serverData'></div>
    </form>
</body>
</html>
  • Lines 9-13 instantiate a WebSocket. For FF, I had to add ‘Moz’ prefix as it is still considered experimental. IE10 uses WebSocket as the standard specifies it.
  • Lines 16-18 simply update the div on line 21 with whatever is being received from the server.

Here’s the server code. As it’s quite lengthy, I have embedded comments within (highlighted lines are explained below):

<%@ WebHandler Language="C#" Class="MyDispatcher" %>

using System;
using System.Text;
using System.Web;
using System.Threading.Tasks;
using System.Threading;
using System.Timers;
using System.Web.WebSockets;
using System.Net.WebSockets;
using System.Collections.Generic;

public class MyDispatcher : IHttpHandler
{
    // list of client WebSockets that are open
    private static HashSet<WebSocket> list = new HashSet<WebSocket>();

    // ensure thread-safety of the WebSocket clients
    private static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

    // timer to simulate server actions which initiate notifications to clients
    private static System.Timers.Timer timer = new System.Timers.Timer();

    // initiate timer
    static MyDispatcher()
    {
        timer.AutoReset = false;
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
        timer.Interval = 10000; // notify every 10 seconds
        timer.Start();
    }

    // when ellapsed, notify all clients what the date/time is
    private async static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer.Stop();

        locker.EnterReadLock();
        try
        {
            if (list.Count == 0)
                return;

            string userMessage = string.Format("server sent: {0}", DateTime.Now);
            var buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMessage));

            foreach (var socket in list)
            {
                if (socket.CloseStatus == null && socket.State == WebSocketState.Open)
                {
                    // asynchronously send a message to the client
                    await socket.SendAsync(buffer, WebSocketMessageType.Text,
                        true, CancellationToken.None);
                }
            }
        }
        finally
        {
            locker.ExitReadLock();
            timer.Start();
        }
    }

    // entry point to the handler, when a client requests to open a WebSocket
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
            HttpContext.Current.AcceptWebSocketRequest(MyWebSocket);
    }

    // web socket async handler
    private async Task MyWebSocket(AspNetWebSocketContext context)
    {
        WebSocket socket = context.WebSocket;

        // add socket to socket list
        locker.EnterWriteLock();
        try
        {
            list.Add(socket);
        }
        finally
        {
            locker.ExitWriteLock();
        }

        // maintain socket
        while (true)
        {
            ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);

            // async wait for a change in the socket
            WebSocketReceiveResult result =
                await socket.ReceiveAsync(buffer, CancellationToken.None);

            if (socket.State == WebSocketState.Open)
            {
                // TODO: handle what the client sent and send a message back from here
            }
            else
            {
                // client is no longer available - delete from list
                locker.EnterWriteLock();
                try
                {
                    list.Remove(socket);
                }
                finally
                {
                    locker.ExitWriteLock();
                }

                break;
            }
        }
    }

    public bool IsReusable { get { return true; } }
}

I’d like to emphasize several things, despite the embedded comments:

  • Line 49: Although the list is supposed to be cleared of non-open WebSockets, it is a safety. This sample did not originally remove closed sockets, and I noticed that accessing sockets in the list just to check if their state was Open, sometimes results in a “cannot access Disposed object” exception. Currently there’s no catch clause in that location as I have not experience this ever since I got rid of them closed sockets, but you may want to consider doing so. BTW: that’s why I also query the nullable CloseStatus prior to querying the Open state: I’m hoping that it won’t result in that exception if there is a CloseStatus – but I added this later in development and I can’t tell for sure if it is really helping.
  • Line 80: That’s where the new opened WebSocket is stored in the list (or rather HashSet).
  • Lines 93-94: This is important: what these lines basically do, is to asynchronously wait for a message from the client. But, it seems like this method returns whenever the socket status changes. So, when await returns, either the WebSocket is open, and it means that the client sent something which can be handled, or the WebSocket is not open, which probably means that it is closing and should be removed from the list of sockets (Line 106).

So, that’s a possible template for having the server send data to the client without being requested to do so by a client request.

Summary:
To make a long story short, WebSockets seem like something that will definitely will be used in web applications in the future, even if just to replace polling. Whether this will lead to an actual architectural change – I haven’t the slightest idea. All I can say is that there are many examples of things that started as something “small” but evolved to a huge success. Who knows – maybe in the future the web will change from a world of a request/response to a more client-server approach?

One thing that does bother me is that IIS7 does not support this feature. For us ASP.NET developers this could really pose a limitation. It’s not that easy to upgrade existing O/S to the newest servers, especially if those servers are customers’ servers, and WebSockets aren’t a good enough reason to do so, at least not yet. I hope that someone at MS will realize that this is a mistake and will help change this decision from within.

Note:
It’s important to note that WebSockets are not a Microsoft-only feature and are an HTML5 concept. This means that it will work on all of the major browsers one day, and as you can see here, it is already supported on Chrome, FF and IE 10.

UPDATE: I urge you to go and read this post too, in which I came to a conclusion that unfortunately WebSockets may not be a full solution as it will be supported from IE10 only.

 
4 Comments

Posted by on 17/02/2012 in Software Development

 

Tags: , , , , , , , ,