Building Real-Time Web Apps with HTTP Streaming in ASP.NET

HTTP streaming—often referred to as Comet—lets the server push information to the browser without waiting for the client to poll. Instead of closing the connection immediately, the server keeps the request open and flushes data as soon as it becomes available. The browser receives the response, processes it, and immediately opens a new request, creating an endless "pull-stream" that behaves like a server push.

How HTTP Streaming Works

In a classic request/response cycle the server replies within milliseconds. In streaming mode the server:

  1. Accepts the request.
  2. Holds it in memory (or on disk) until data is ready or a timeout occurs.
  3. Sends the payload and terminates the request.
  4. The client instantly repeats step 1.

During the small gap between the end of one request and the start of the next, any new events are queued and delivered in the subsequent request.

Mapping to Socket Semantics

Each browser keeps one "downlink" connection (server → browser) alive at all times. Ordinary GET/POST requests (browser → server) are still allowed on separate connections. If Browser-1 posts a message, the server can instantly flush it to Browser-2 through its open downlink, giving us the illusion of full-duplex communication.

Implementing Srteaming in ASP.NET

The easiest way to implement this pattern in ASP.NET is to use the asynchronous HTTP handler interface IHttpAsyncHandler. The key methods are:

  • BeginProcessRequest – starts an async operation and returns an IAsyncResult without finishing the response.
  • EndProcessRequest – completes the respnose once data is ready.

Because EndProcessRequest is not invoked immediately, the connection remains open. When the server decides to push data, it writes to HttpResponse and then calls EndProcessRequest, closing the request. The client receives the payload and instantly starts a new long-lived request.

Sample Protocol

All payloads are JSON. The server can send single frames or a batch:

{
  "type": "login",
  "login_name": "alice",
  "login_time": "2023-08-11 09:15:00"
}

{
  "type": "sendmsg",
  "msg": "Hi Bob!",
  "send_name": "alice",
  "send_time": "2023-08-11 09:15:03"
}

{
  "type": "data_list",
  "list": [
    { "type": "login", "login_name": "bob", "login_time": "..." },
    { "type": "sendmsg", "msg": "Hello!", "send_name": "bob", "send_time": "..." }
  ]
}

Client-Side Loop

function openStream() {
    $.ajax({
        url: 'stream.ashx',
        type: 'post',
        data: { uid: currentUser },
        dataType: 'json',
        success: function (packet) {
            switch (packet.type) {
                case 'login':      addUser(packet);      break;
                case 'sendmsg':    appendMsg(packet);    break;
                case 'logout':     removeUser(packet);   break;
                case 'data_list':
                    packet.list.forEach(openStream);    // recurse per item
                    break;
            }
            openStream();           // immediately reopen channel
        },
        error: function () {
            setTimeout(openStream, 1000); // reconnect on failure
        }
    });
}

Running the Demo

A minimal chat room is included in the downloadable project. Each tab keeps one hanging GET request; most browsers limit concurrent connections to six per host, so avoid opening too many tabs in the same browser.

Tags: ASP.NET Comet HTTP streaming IHttpAsyncHandler Real-Time Web

Posted on Tue, 20 Oct 2026 16:48:55 +0000 by Brian Swan