[C#]ASP.NET and Comet: Bringing Sockets Back

Sample Image

Introduction

Web pages and ASP.NET are wonderful tools, but as the old proverb goes, "if all you have is a hammer, everything seems like a nail". ASP.NET is a web technology, all of which exists to serve up resources to Web Browsers which request them. That's great, and it works for the vast majority of things currently on the Internet. In fact, when people think of the Internet, they mostly associate it with the ubiquitous World Wide Web model or its HTTP protocol. But, what if we want more…what if instead of Web Browsers just requesting resources, we want to push information actively out to them, without being asked first? Examples of this include: live wiki's, polls, chat, stock tickers, real-time auctions, and games.

This is where the existing paradigm fails, and we have to fall back to older technologies, the roots on which the Internet is founded….yes, I'm talking about actual two-way communication, interactivity, *gasp* sockets, TCP/IP!

Taking a step back, web requests can roughly be compared to a student asking a teacher questions. However, only the student is allowed to ask questions, the teacher cannot actively prompt the student with facts. This article sets out one experimental approach to breaking that model. Most of the current solutions, collectively called "Comet", involve the Web Browser keeping an active HTTP connection to the Web Server, like a student always keeping the teacher's attention. Presented here is another aproach, utilizing a "side-channel", where the "teacher" (that's the Web Server) doesn't spend as much attention or resources responding to pesky questions (web requests), and we can push information out instead, or engage in a more interactive way.

Background

This article is inspired and partially based on the work and code by Alex MacCaw, the developer who created the Juggernaut extension to Ruby on Rails. But, why leave all the fun to those dynamic language people? Can't we have that in ASP.NET too? The answer is "yes we can".

How do we communicate with the Web Browser without it making a request first? One solution is to have the Web Browser keep open a socket connection directly to the server using a small light-weight Flash component.

What are the benefits of this aproach?

  • It consumes much less Web Server resources. We are not dedicating any Web Server threads to responding to a "long-polling" request.
  • It's simple and easy to implement.
  • Good cross-platform support (any modern Web Browser that supports Flash 8, e.g., IE, FireFox, Safari, Opera).
  • Lower latency, no re-establishing connections, or other HTTP protocol overheads.

And yes, it does have drawbacks:

  • We need to install something on the Web Server or the network domain to accept these socket connections.
  • The embedded Flash component making the connection to the Comet server will not work behind firewalls or proxies that block non-HTTP ports.
  • It needs Flash and JavaScript enabled on the Web Browser.
  • It's a hack (though the same thing could be said about many, now ubiquitous, Web Browser technologies).

Using the Code

Comet applications can be divided into two categories:

  • "Server-push" applications where the Web Server pushes out information on updates and changes based on user events, e.g., live wiki's, polls, chat etc.
  • "Interactive" applications where an external process pushes information to the web browser in response to an event, e.g., stock tickers, real-time auctions, games etc.

Server-push

The work flow for using Comet in a server-push scenario is:

  1. The Web Browser requests a page from the Web Server, which includes the Flash Comet component, Comet JavaScript, and a unique authentication string.
  2. The Web Server registers the Comet connection with the "Comet Server", specifying its channel, its authentication string, and any initial state.
  3. The Web Browser opens a socket connection to the Comet Server, and sends its authentication string.
  4. The Web Browser sends data to the Web Server using postbacks.
  5. The Web Server responds to any postbacks or AJAX calls and publishes any updates to the Comet Server.
  6. The Web Browser responds to any updates from its Comet connection.

In code, with a simple "GuestBook" example:

  1. Placing a "CometControl" on the ASP.NET web page:
  2. Collapse
    <CometControl
    id="cometControl"
    runat="server"
    channel="GuestBook"></CometControl>
  3. Registering the Comet connection:
  4. Collapse
    protected void Page_Load(object sender, EventArgs e)
    {
    if (!IsPostBack)
    cometControl.Register();
    }
  5. Opening a socket is done automatically on the Web Browser if the "AutoConnect" property is set to true (the default).
  6. AJAX postbacks can be done with a simple UpdatePanel using ASP.NET AJAX extensions.
  7. The Web Server responds to AJAX events by publishing JavaScript code that is automatically evaluated on the Web Browser.
  8. Collapse
    protected void submitButton_Click(object sender, EventArgs e)
    {
    string name = nameTextBox.Text.Trim();
    string text = commentTextBox.Text.Trim();
    if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(text))
    {
    cometControl.Data = "guestbook_addComment ("
    + Wxv.Comet.Utility.SerializeJSON(
    HttpContext.Current.Server.HtmlEncode(name))
    + "," + Wxv.Comet.Utility.SerializeJSON(
    HttpContext.Current.Server.HtmlEncode(text)) + ");";
    cometControl.Publish();
    }
    commentTextBox.Text = "";
    }
  9. Finally, the Web Browser receives the data published on the Web Server and executes it:
  10. Collapse
    guestbook_addComment = function(name, comment)
    {
    var commentsDiv = document.getElementById ("comments");
    var e = document.createElement("blockquote");
    e.innerHTML = comment + " - " + name + "";
    commentsDiv.insertBefore (e, commentsDiv.firstChild);
    }

Interactive

The interactive scenario is very similar, but instead of the Web Browser doing postbacks or AJAX calls to the Web Server, the Web Browser uses its Comet connection to send data directly to an Application Client and vice versa.

The work flow for using Comet in an interactive scenario is:

  1. The Web Browser requests a page of the Web Server, which includes the Flash Comet component, Comet JavaScript, and a unique authentication string.
  2. The Web Server registers the Comet connection with the "Comet Server", specifying its channel, its authentication string, and any initial state.
  3. The Web Browser opens a socket connection to the Comet Server, and sends its authentication string, and the Comet Server tells any Application Clients whether a connection has been made on a channel they have subscribed to.
  4. The Application Client sends data to the Comet Server, which passes it onto any Web Browser which has connected on that channel.
  5. The Web Browser sends data to the Comet Server over its Comet connection, which passes it onto any Application Client which has subscribed to that channel.

The Web Browser code is still very similar, but now, instead of doing AJAX calls or postbacks, we can just send data to our actively listening Application Client over the Comet connection.

E.g.: in response to a button click in a "sound player" application:

Collapse
function sounds_click(soundId)
{
comet.send (soundId);
}

The Comet Server and Clients

The Comet Server is a simple event handling and messaging component that accepts two types of connections:

  • Comet connections from Web Browsers, these are always pre-registered and associated with a single channel.
  • Client connections from the Web Server, Comet Controls, or Client Applications.

It responds to the following Client events:

  • Register – A Client wants to allow a Web Browser to make a Comet connection.
  • Subscribe – A Client wants to listen to events on a specific channel.
  • Publish/Push – A Client wants to send data to an entire channel (Publish) or a specific Comet connection (Push).

It sends the following events to any Client that has subscribed to the related channel.

  • Connect – A Web Browser has successfully connected and authenticated with the Comet Server.
  • Disconnect – An authenticated Web Browser has disconnected from the Comet Server.
  • Send – A Web Browser has sent data to the Comet Server.

Both the Comet Server and the Client component, which Application Clients can be written with, are simple components. The Comet Server component is self-contained, the only interaction needed is to get it to start and stop, and it can be easily hosted in a Windows application, a Service, or even in the Web Server itself. Similarly, the Client is a simple component (which the CometControl already encapsulates) which exposes some simple methods and events (on a single thread) which can easily be extended to write your own Application Clients which can also be hosted in a variety of ways.

Summary

Web browsers opening socket connections to a server isn't actually that new. In their isolated little sandboxes, Java applets have been doing it since they were invented more then a decade ago, and Flash has had the capability for a while too. Microsoft's Silverlight will eventually be getting it in version 2.0. All that the Comet approaches are trying to do is get a similar capability directly within the web browser itself.

I've had fun with this project, exploring a Comet solution for ASP.NET. I don't pretend that it's anything more than it is, a toy project; so consume and eat it with a grain of salt (and credit me if it tastes nice). For this author however, it gave an interesting insight to what's possible.

History

  • 7-Apr-2008 – First version!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Wilfred Verkley

Im a Software Developer working in Auckland, New Zealand. When i was a lot shorter, i started programming in Atari Basic, though these days its mostly C#, and a bit of java (mostly the caffinated kind).
赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏