WebSockets for Faster, More Scalable Ajax Applications
If you want to call a service you can—but the service can't call you back. WebSockets offers the potential for real, two way communications -- and it's as simple as calling a Web Service.
The idea behind WebSockets is simple: the client requests a TCP socket to communicate with the service. Once the socket's created, the client and the server can use it to send messages to each other. WebSockets' impact should be tremendous, both in improving the performance of Ajax applications and their scalability. There are two reasons for this: First, WebSockets uses TCP (better performance than HTTP); Second, WebSockets implements two-way communication between a consumer and a service. For Ajax, that two-way communication isn't just better, it's new.
Currently, with Ajax, all communication is initiated by the consumer—the service can't call the client. With WebSockets, the service can send data to the client whenever the data is ready, eliminating the need for client to continually check if there's anything waiting for it at the service. Two-way communication substantially reduces the demands on services, improving their scalability. Two-way communication also enables more powerful Ajax applications that can, for instance, accept notifications from a service when something has changed at the service.
One final note: Since this is new technology in a pre-release version (at least for Internet Explorer), take this code as a guideline only.
The new API revolves around the WebSocket object. When you instantiate a WebSocket, you pass a URL that specifies the service you'll connect to (you can optionally pass an array of protocol names and, if the service doesn't support any of those protocols, the service can reject the request). The standard protocol is ws and the URL should end with a resource name. This example specifies the customer resource and includes an explicit port number:
wskt = new WebSocket('ws://myserver.com:1867/customers');
The resulting WebSocket object has a readystate property that reports the status of the connection (Connecting, Open, Closing, Closed). More usefully, the WebSocket object fires an onopen event to which you can tie a function. You can use that to trigger some initial processing (assuming you need to do any—your client might just wait for messages from the service). To send a message to the service to which you've connected, you use the WebSocket's send method to send strings, a binary large object, or a fixed-length binary array. This code uses jQuery to retrieve the value from an element with an id attribute to set to CompanyId, and sends that value to a service (after passing the value through the JSON object's stringify method):
The send method actually just queues up your transmissions -- you're not guaranteed that your message is actually being delivered (at least, not immediately). To find out if your messages aren't getting through, you can check the WebSocket's bufferedAmount property to determine how much data is still waiting to be sent.
To receive messages from the service, you attach a function to the WebSocket's onmessage event (the API also supports the new DOM3 Event model). That function can accept a single parameter which may a string, a BLOB or a fixed length binary array. This code wires up a function that checks to see if the returned message is a string and, if so, uses jQuery to update an element with an id attribute of CompanyName:
wskt.onmessage = function (incoming)
var data = JSON.parse(incoming);
if (typeof data == 'string')
If you don't need a connection anymore you can close it, using the WebSocket's close method. This code checks to see if the WebSocket's readystate isn't already set to closed before calling the close method:
if (wskt.readyState !== 1)
To reopen the connection you must create a new WebSocket object (there is no open method on the WebSocket).
WCF Server-side Processing
The Prototype download includes these libraries. To add a reference to them to your project, select the Browse Tab in the Add Reference and look for the libraries in a subfolder of the /Program Files/Microsoft SDKs/WCF WebSockets folder.
To create a client that handles requests and sends responses, create a class that inherits from Microsoft.ServiceModel.Websockets.WebSocketsService and override at least one of the OnMessage methods; either the version that accepts a string or the version that accepts a byte array. Since my client is sending a string, for this example, I override the version that accepts a string:
<ServiceBehavior(InstanceContextMode := InstanceContextMode.PerSession,
ConcurrencyMode := ConcurrencyMode.Multiple)>
Public Overrides Sub OnMessage(Incoming As String)
'code to process incoming message
Since this one method will be accepting all of the messages from the client that uses this URL, you'll need to either design a message format that makes it easy to parse out your client's requests or have only one kind of message accepted at any URL. For instance, if the only message sent to the URL is a CustomerID and the result is always the CompanyName, you don't need to worry about the message format. If, on the other hand, you want this single URL to accept messages for retrieving, updating, deleting and inserting Customers, you'll need a more structured incoming message.
To send a message back to the client that's contacted the service, use the WebSocketsService SendMessage method. This example sends a message back to the client to indicate that the service is ready to accept messages:
As you might expect, there are two versions of the SendMessage method: one that sends a string and one that sends a byte array.
The easiest way to test your service is to create a host as a Console Application (in real life, this would be a Windows Service). You must create a WebSocketHost, passing the type of the class you created to handle communication with the application. After you've created the host, call its AddWebSocketsEndpoint method, passing the URL you used in the client to contact the client. Finally, you should call the WebSocketsHost's Open method, followed by a call to Console.ReadLine to keep your Console in memory. In Visual Basic, this code would go into the Sub Main routine:
Dim wsh As New Microsoft.ServiceModel.WebSockets.WebSocketsHost
In C#, the code would go in the Program.cs file:
WebSocketsHost<Customers> wsh =
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.