HTML5 WebSockets allow you to perform two-way (duplex) communication between the client browser and the server. ASP.NET 4.5 and IIS 8 provide support for WebSocket protocol so that you can program WebSockets in your ASP.NET web forms and ASP.NET MVC applications. This article discusses what WebSockets are and how to develop web applications that take advantage of HTML5 WebSockets.
Overview of HTML5 Web Sockets
Typically a communication over the web is comprised of two distinct parties participating in the communication, viz. the client and the web server. An ordinary web page uses a request-response model of communication wherein the browser sends a request to the server and the server then sends back a response. Each request and response uses a new connection and that connection is closed once the response is returned by the server. As you might have guessed, such a communication is poor in terms of performance since a new connection is established between the same client and the server every time. Additionally, such a communication can't be two way, i.e. client talking to server and server talking to the client simultaneously.
In the case of two-way or duplex communication both the parties participating in the communication can communicate at the same time. A common application of the duplex communication is chat systems such as MSN or Yahoo Messenger and Google Talk. In any chat system, two or more members can chat with each other at the same time. As far as HTML5 is concerned, the technique to achieve two way communications is Web Sockets.
Unlike the request-response model, WebSockets keep the underlying communication channel open throughout the course of communication. A WebSocket based communication typically involves three steps:
- Establishing a connection between the client and the server or Hand Shake.
- Asking the Web Socket server to listen to the incoming communication
- Sending and receiving data
Web applications use HTTP protocol for their functioning and HTTP protocol essentially makes use of the request-response model. The plain HTTP protocol isn't well suited for performing two-way communications. The WebSockets therefore, need to "upgrade" the plain HTTP protocol to WebSocket protocol. This "upgrade" takes place while establishing the connection between the client and the server. In order to upgrade the communication from plain HTTP to WebSocket, you need a web server that is capable of doing this upgrade.
Enabling WebSocket Protocol in Windows 8
As far IIS is concerned, IIS 8.0 that ships with Windows 8 is capable of accepting Web Socket communications. If you are developing a web application that makes use of HTML5 Web Sockets, you may need to install WebSocket support in IIS 8.0. The following figure shows the "Turn Windows features on or off" option from the control panel. It can be used to install WebSocket protocol.
Notice how the "WebSocket Protocol" feature is checked under "World Wide Web Services". If the IIS installation doesn't have WebSocket protocol enabled your ASP.NET applications won't be able to receive and respond to the WebSocket requests on the server.
A WebSocket based application consists of two parts, viz. WebSocket server side code and WebSocket client side code. The WebSocket server side code sits on the web server and "listens" to the incoming communication from clients. When some communication is received from the client it processes the communication and typically sends some communication back to the client. If there is no communication from the client the WebSocket server can either keep waiting for the communication or can terminate the communication channel. The WebSocket client side code makes use of the WebSocket object of HTML5 for the purpose of sending and receiving data to and from the WebSocket server side code.
The WebSocket client side code follows the same coding pattern regardless of your web server software. As far as ASP.NET is concerned, IIS 8 and certain .NET framework classes together allow you to develop WebSocket server side functionality. To understand how the client side and server side code goes hand in hand let's develop a simple application that performs a two-way communication. The web form that acts as a WebSocket client is shown below:
Using the above web form you can send a text message from the client to the server. The server then sends the same message back to the client (this is purely for the sake of simplicity and testing purposes. You can send any other data from the server. Clicking on the Stop button stops the server and no further communication can take place between the client and the server.
Coding the Client Side
Open the default web form and add the following jQuery code to a <script> block:
var socket;
$(document).ready(function () {
socket = new WebSocket("ws://localhost:1046/WebSocketGenericHandler.ashx");
socket.addEventListener("open", function (evt) {
$("#divHistory").append('<h3>Connection Opened with the Echo server.</h3> ');},
false);
socket.addEventListener("message", function (evt) {
$("#divHistory").append('<h3^gt;' + evt.data + '</h3> '); },
false);
socket.addEventListener("error", function (evt) {
$("#divHistory").append('<h3>Unexpected Error.</h3> ');},
false);
...
});
The code shown above declares a global variable named socket to hold a reference to a WebSocket object. A WebSocket instance is then created by passing the URL of the WebSocketHandler.ashx. The WebSocketHandler.ashx contains the WebSocket server side code that "listens" to the client requests. You will develop WebSocketHandler.ashx later in this article. Notice how the URL uses ws:// protocol instead of http://. Next, event handlers for the three events, viz. open, message, and error, are wired using the addEventListener() method. The open event is raised when the readyState property (discussed next) changes to 1 (OPEN) and indicates that the connection is ready to send and receive data. The message event is raised when a message is received from the WebSocket server. The error event is raised when an error occurs during the communication with the Web Socket server.
Inside the message event handler the data sent by the server is retrieved using the evt.data property. The returned data is then appended to a <div> element. The other event handlers simply output the specified messages in the <div> element. The data from the client is sent to the server when the Send button is clicked. The click event handler of the Send button looks like this:
$("#btnSend").click(function () {
if (socket.readyState == WebSocket.OPEN) {
socket.send($("#txtMsg").val());
}
else {
$("#divHistory").append('<h3>The underlying connection is closed.</h3> ');
}
});
The click event handler of the Send button checks the readyState property of the WebSocket object. If the readyState is OPEN, it calls the send() method on the WebSocket instance. This read only property returns the current state of the connection. Possible values are 0 - CONNECTING, 1 - OPEN, 2 - CLOSING, 3 - CLOSED. The send() method sends data to the WebSocket server side code over an established connection. The text entered in the textbox is passed as a parameter to the send() method.
You can close the underlying connection by calling the close() method of the WebSocket object as follows:
$("#btnStop").click(function () {
socket.close();
});
Coding the Server Side
The WebSocketHandler.ashx contains the server side code that listens and responds to the client requests. This code is shown below:
public class WebSocketHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(DoTalking);
}
}
...
}
The above code shows an ASP.NET generic handler - WebSocketHandler - that triggers the WebSocket server. The ProcessRequest() method of the generic handler first checks whether the incoming request is a WebSocket request. This is done by checking the IsWebSocketRequest property of the HttpContext object. This property works hand-in-hand with the IIS 8.0 WebSocket module and returns true if an incoming request is a WebSocket request. A Web Socket request is different than an ordinary HTTP request in that instead of using http:// protocol it uses ws:// (Web Socket) protocol.
If the IsWebSocketRequest returns true, the AcceptWebSocketRequest() method of the HttpContext is called. This method takes one parameter - user function - that supplies a function that listens and responds to the client requests. In this case the user function contains the logic to listen to the incoming data and send it back to the client. The user function supplied to the AcceptWebSocketRequest() method should be an asynchronous function as shown below:
public async Task DoTalking(AspNetWebSocketContext context)
{
WebSocket socket = context.WebSocket;
while (true)
{
ArraySegment buffer = new ArraySegment(new byte[1024]);
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (socket.State == WebSocketState.Open)
{
string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
userMessage = "You sent: " + userMessage + " at " + DateTime.Now.ToLongTimeString();
buffer = new ArraySegment(Encoding.UTF8.GetBytes(userMessage));
await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
else
{
break;
}
}
}
The DoTalking() method is marked as "async" indicating that the code inside it is going to run in asynchronous fashion. The DoTalking() method returns a Task object. The Task class acts as a wrapper to the asynchronous code. The DoTalking() method receives a parameter of type AspNetWebSocketContext. The AspNetWebSocketContext class gives you access to the WebSocket through its WebSocket property. The WebSocket class is the server side counterpart of the HTML5 WebSocket object. An endless while loop is then started so that the server can continuously listen to the incoming requests. To receive the incoming data, the ReceiveAsync() method of the WebSocket class is used. The ReceiveAsync() method is invoked along with the await operator. In this case the awaited task is to receive incoming data and store it in an ArraySegment, a byte array. The results of the receive operation are stored in WebSocketReceiveResult object. If the WebSocket is open as indicated by the State property, the received data is sent back to the client using the SendAsync() method. If the State property has any value other than Open, the while loop is exited thus terminating the server.
Summary
HTML5 WebSockets allow you to perform two-way (duplex) communication. To use HTML5 WebSockets in an ASP.NET application you need to enable the WebSocket protocol in IIS 8.0. You can then use IsWebSocketRequest property and AcceptWebSocketRequest() method to start the client-server communication. Using WebSockets, you can develop web applications such as Chat systems that require the ability to send and receive data simultaneously between the client and the server.