WebSockets is cool, but what can you do today?

WebSockets is a new feature that appears to be a great way to send messages from the server to the browser, however today there isn’t much support, both in browsers and on the server in IIS and ASP.Net.

Today you can use a Comet technique (in particular, Ajax with long polling) which is available in all browsers. Using this concept, the browser makes a standard AJAX call to the server that waits until it receives a message. Asynchronous Pages and Asynchronous Controller allow you to have long running HTTP requests without using precious ASP.Net threads.

On the server, there are two resource limits to consider with IIS and ASP.Net:

  • HTTP request limits — in IIS7 the default limit is 5000
  • ASP.Net thread limits — in IIS7 the default limit is 12 x number of CPUs

For a typical ASP.Net application (and ASP.Net MVC application), an HTTP request always uses an ASP.Net thread. However you can use Asynchronous Pages in ASP.Net or Asyncronous Controllers in ASP.Net MVC to free the ASP.Net thread (but still keep the HTTP request). Using Asynchronous Pages or Controllers is ideal for Comet HTTP requests.

Take for example an email web application that has jQuery code to check for new mail. It calls /CheckEmail which returns either true or false. As soon as it completes it calls checkEmail() immediately so that it can be notified of any new mail.

        $(function () {
            checkEmail();
        });

        function checkEmail() {
            $.post("/CheckEmail", null, function (data, s) {
                if (data.d) {
                    $('#emailCheck').text('You have mail!');
                } else {
                    $('#emailCheck').text('No change.');
                }

                checkEmail();
            });
        }

On the server, the code uses the AsyncController to free the ASP.Net thread for other HTTP requests until this HTTP request has completed.

    public class CheckEmailController : AsyncController
    {
        //
        // GET: /CheckEmail/

        public void IndexAsync()
        {
            AsyncManager.OutstandingOperations.Increment();
            MyAsyncEmailChecker.CheckForEmailAsync(hasEmail =>
            {
                AsyncManager.Parameters["hasEmail"] = hasEmail;
                AsyncManager.OutstandingOperations.Decrement();
            });
        }

        private class IndexResponse
        {
            public bool d { get; set; }
        }

        public JsonResult IndexCompleted(bool hasEmail)
        {
            return this.Json(new IndexResponse() { d = hasEmail });
        }

    }

There are three phases on the server.

        public void IndexAsync()
        {
            AsyncManager.OutstandingOperations.Increment();
            MyAsyncEmailChecker.CheckForEmailAsync(/* callback function */);
        }

The first phase calls AsyncManager.OutstandingOperations.Increment() and MyAsyncEmailChecker.CheckForEmailAsync. When AsyncManager.OutstandingOperations is zero, the matching “Completed” method is called. This increment prevents the Completed method from being called before the data is ready. Next the code initiates an Async call to MyAsyncEmailChecker.CheckForEmailAsync(). This is a method I wrote, and in fact it just a demo class for this article. It returns immediately and then calls the callback function 5 seconds later. “Async” functions are common in the .Net framework, for example:

            /* an Async function */(hasEmail =>
            {
                AsyncManager.Parameters["hasEmail"] = hasEmail;
                AsyncManager.OutstandingOperations.Decrement();
            })

The next phase calls the function passed in when the MyAsyncEmailChecker finishes. It sets the return data in the AsyncManager.Parameters collection. These are the same parameters found in the IndexCompleted method. Next the code calls AsyncManager.OutstandingOperations.Decrement(). Now that AsyncManager.OutstandingOperations is zero, ASP.Net MVC will call IndexCompleted().

        public JsonResult IndexCompleted(bool hasEmail)
        {
            return this.Json(new IndexResponse() { d = hasEmail });
        }

The IndexCompleted method returns the data to the browser — in this case it is a JsonResult.

Lastly, most browsers limit 2 HTTP connections to the same server, though recent browsers do not have this limitation. If the browser has a long running HTTP connection to recent messages from the server, it is using one of your two HTTP connections.

UPDATE 2011-05-20: You can download the full source code here.

About Clay Lenhart

I am a DBA/Technical Architect for Latitude Group and love technology.
This entry was posted in ASP.Net and tagged , , , , , . Bookmark the permalink.

9 Responses to WebSockets is cool, but what can you do today?

  1. Cyril Gupta says:

    Excellent article Cley.

    I’ve used ‘long-polling’ to get the newest updated blogs on my programming blogs aggregator http://codebix. I used a timer to poll the server intermittently, but certainly the method you’ve suggested is much superior.

    I need to wrap my head around Asynchronous features of MVC and implement them.

    Thanks

  2. yiming says:

    Thanks Cley,
    but I would like to know what’s the details in the View (jQuery) & Controller (/CheckEmail)

    Could you please share the code?

  3. Clay Lenhart says:

    yiming,
    There is no view since the controller returns a JsonResult. The controller is above: CheckEmailController.

    I think a complete working project is something you would want. The project is long gone however. I’ll recreate it if I have time.

  4. Clay Lenhart says:

    yiming, I found the code and uploaded it.

  5. pablo says:

    Hi! i have a question. from javascript i dont need to write any code for comet? i read some articles where the used some libraries to work with comet because it uses another protocol (Bayeux).

    How can i do to test the long poll? with a beakpoint in the controller and then see what happens in the browser?

    i found some products for this kind of apps (ei: http://www.frozenmountain.com/websync/), and seem that they have a lot of coding to acomplish the comet solution. What you say in this article is that with a simple MVC controller and jquery i can do the same as this kind of expensive prods?

    Regards!

  6. Clay Lenhart says:

    Pablo,
    The above technique works, with a couple of points to be aware of:
    * It’s simple. There’s no connection management, no channels, no streaming. The technique above is what you get.
    * There is no message framework included on the server, which you’ll need to provide. When the server wants to send a message to the client, it’ll have to put the message temporarily somewhere for the client to pick up later when it polls for more messages. This might be a database table or a real message queue.

    You can set a breakpoint anywhere on the server. Many browsers offer a way to step through javascript code on the client (Firebug for instance).

  7. QB says:

    hey, Clay! Thank you soooooo much. :smile:

  8. Pingback: Long Poll Sally – ASP.NET MVC AsyncController « I Came, I Learned, I Blogged

  9. Pingback: Asp.net 3.5 and MVC 2,IE 8 – 10 compatiblility matters to the client. I need to implement real time notifications like facebook,gmail | StackAnswer.com

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>