Click here to Skip to main content
15,867,308 members
Articles / Web Development / ASP.NET

Using WebSocket in .NET 4.5 (Part 2)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
15 Jul 2013CPOL2 min read 221.5K   15.1K   58   18
Using WebSocket in traditional ASP.NET and MVC 4

Introduction

Part 1 gives an overview to WebSocket protocol and .NET WebSocket support.

In this article, I will demonstrate how to host a WebSocket server in a traditional ASP.NET or MVC 4 web application using HttpContext.AcceptWebSocketRequest. I will show JavaScript code in client-side web page. I will also show a client-side application to communicate with the same server using the ClientWebSocket class in the System.Net.WebSockets namespace.

Preparation

To enable WebSocket on the server side, please refer to Part 1.

Traditional ASP.NET

To host a WebSocket server, I create a custom HTTP handler to accept client WebSocket connection requests and communicate with the client.

C#
public class WSHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            context.AcceptWebSocketRequest(ProcessWSChat);
        }
    }

    public bool IsReusable { get { return false; } }

    private async Task ProcessWSChat(AspNetWebSocketContext context)
    {
        WebSocket socket = context.WebSocket;
        while (true)
        {
            ArraySegment<byte> buffer = new ArraySegment<byte>(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<byte>(
                    Encoding.UTF8.GetBytes(userMessage));
                await socket.SendAsync(
                    buffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else
            {
                break;
            }
        }
    }
}

In the ProcessRequest method, I check whether HttpContext.IsWebSocketRequest is true. True means the request is an AspNetWebSocket (System.Web.WebSockets) request. Then, I call HttpContext.AcceptWebSocketRequest to accept the request and establish the connection. I pass in a method as the argument. This method contains code to do the duplex communication through AspNetWebSocketContext.WebSocket. Here, I just echo what the client has sent to the server.

Don’t forget to register the HTTP handler in web.config:

XML
<system.webServer>
    <handlers>
      <add path="/WSChat/WSHandler.ashx" verb="*" name="WSHandler"
           type="WSChat.WSHandler"/>
    </handlers>
</system.webServer>

In the web page, I write JavaScript code to communicate with the server:

HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>WebSocket Chat</title>
    <script type="text/javascript" src="Scripts/jquery-2.0.2.js"></script>
    <script type="text/javascript">
        var ws;
        $().ready(function () {
            $("#btnConnect").click(function () {
                $("#spanStatus").text("connecting");
                ws = new WebSocket("ws://" + window.location.hostname +
                    "/WSChat/WSHandler.ashx");
                ws.onopen = function () {
                    $("#spanStatus").text("connected");
                };
                ws.onmessage = function (evt) {
                    $("#spanStatus").text(evt.data);
                };
                ws.onerror = function (evt) {
                    $("#spanStatus").text(evt.message);
                };
                ws.onclose = function () {
                    $("#spanStatus").text("disconnected");
                };
            });
            $("#btnSend").click(function () {
                if (ws.readyState == WebSocket.OPEN) {
                    ws.send($("#textInput").val());
                }
                else {
                    $("#spanStatus").text("Connection is closed");
                }
            });
            $("#btnDisconnect").click(function () {
                ws.close();
            });
        });
    </script>
</head>
<body>
    <input type="button" value="Connect" id="btnConnect" />
    <input type="button" value="Disconnect" id="btnDisconnect" /><br />
    <input type="text" id="textInput" />
    <input type="button" value="Send" id="btnSend" /><br />
    <span id="spanStatus">(display)</span>
</body>
</html>

The code of the standalone client application looks like:

C#
class Program
{
    private static async Task ChatWithServer()
    {
        using (ClientWebSocket ws = new ClientWebSocket())
        {
            Uri serverUri = new Uri("ws://localhost/WSChat/WSHandler.ashx");
            await ws.ConnectAsync(serverUri, CancellationToken.None);
            while (true)
            {
                Console.Write("Input message ('exit' to exit): ");
                string msg = Console.ReadLine();
                if (msg == "exit")
                {
                    break;
                }
                ArraySegment<byte> bytesToSend = new ArraySegment<byte>(
                    Encoding.UTF8.GetBytes(msg));
                await ws.SendAsync(
                    bytesToSend, WebSocketMessageType.Text, 
                    true, CancellationToken.None);
                ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[1024]);
                WebSocketReceiveResult result = await ws.ReceiveAsync(
                    bytesReceived, CancellationToken.None);
                Console.WriteLine(Encoding.UTF8.GetString(
                    bytesReceived.Array, 0, result.Count));
                if (ws.State != WebSocketState.Open)
                {
                    break;
                }
            }
        }
    }

    static void Main(string[] args)
    {
        Task t = ChatWithServer();
        t.Wait();
    }
}  

ClientWebSocket (System.Net.WebSockets) plays the role to communicate with the WebSocket server hosted in IIS. Both ClientWebSocket and AspNetWebSocket are inherited from System.Net.WebSockets.WebSocket. So the usage is consistent. Note that the client application can only work on Windows 8, Windows Server 2012 and above.

MVC 4

I implement the same echo function in a MVC 4 web application. I create an ApiController to handle WebSocket requests. In the Get method, I still use HttpContext.AcceptWebSocketRequest to accept and establish connections:

C#
public class WSChatController : ApiController
{
    public HttpResponseMessage Get()
    {
        if (HttpContext.Current.IsWebSocketRequest)
        {
            HttpContext.Current.AcceptWebSocketRequest(ProcessWSChat);
        }
        return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
    }
    private async Task ProcessWSChat(AspNetWebSocketContext context)
    {
        WebSocket socket = context.WebSocket;
        while (true)
        {
            ArraySegment<byte> buffer = new ArraySegment<byte>(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<byte>(
                    Encoding.UTF8.GetBytes(userMessage));
                await socket.SendAsync(
                    buffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else
            {
                break;
            }
        }
    }
} 

The JavaScript code in my index.cshtml is almost the same as the example I have shown before. The only difference is the URI used to send WebSocket connection request. It follows the MVC URI style:

HTML
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script type="text/javascript" src="Scripts/jquery-2.0.2.js"></script>
    <script type="text/javascript">
        var ws;
        $().ready(function () {
            $("#btnConnect").click(function () {
                $("#spanStatus").text("connecting");
                ws = new WebSocket("ws://" + window.location.hostname + 
                    "/Mvc4WSChat/api/WSChat");
                ws.onopen = function () {
                    $("#spanStatus").text("connected");
                };
                ws.onmessage = function (evt) {
                    $("#spanStatus").text(evt.data);
                };
                ws.onerror = function (evt) {
                    $("#spanStatus").text(evt.message);
                };
                ws.onclose = function () {
                    $("#spanStatus").text("disconnected");
                };
            });
            $("#btnSend").click(function () {
                if (ws.readyState == WebSocket.OPEN) {
                    ws.send($("#textInput").val());
                }
                else {
                    $("#spanStatus").text("Connection is closed");
                }
            });
            $("#btnDisconnect").click(function () {
                ws.close();
            });
        });
    </script>
</head>
<body>
    <input type="button" value="Connect" id="btnConnect" />
    <input type="button" value="Disconnect" id="btnDisconnect" /><br />
    <input type="text" id="textInput" />
    <input type="button" value="Send" id="btnSend" /><br />
    <span id="spanStatus">(display)</span>
</body>
</html>

Summary

Next in Part 3, I will demonstrate how to use WCF to host WebSocket server and how to communicate WebSocket WCF service using WCF client application or JavaScript in a web page.

Related Links

Using WebSocket in .NET 4.5

License

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


Written By
Architect
China China
Over 10-years experience in using Microsoft technologies.
At present, working as the architect of a clustered real-time data delivery and visualization system, responsible for the design of component architecture, product packaging and deployment, also targeting private cloud solutions for future.

Comments and Discussions

 
QuestionWebsocket connection failed Pin
Mekala V 202127-Aug-21 5:54
Mekala V 202127-Aug-21 5:54 
QuestionError 503 Service Unavailable Pin
Member 1384910912-Jun-18 4:05
Member 1384910912-Jun-18 4:05 
QuestionHard-coded While Loop purpose? Pin
Jeff Skee24-May-17 11:41
Jeff Skee24-May-17 11:41 
Questionsend msg to specified client (browser client) Pin
cheng.john16-Nov-15 19:22
cheng.john16-Nov-15 19:22 
QuestionNot seeing onmessage fire Pin
Julia_H14-Sep-15 5:47
Julia_H14-Sep-15 5:47 
QuestionThanks ! Pin
PrasunT29-Aug-15 20:33
PrasunT29-Aug-15 20:33 
AnswerRe: Thanks ! Pin
PrasunT29-Aug-15 22:11
PrasunT29-Aug-15 22:11 
QuestionConfirmed working in Win8 w/ IIS8 and VS2013 community Pin
Member 1073592617-Jan-15 16:09
Member 1073592617-Jan-15 16:09 
QuestionServer installation fails Pin
avigalim200025-Jun-14 5:41
avigalim200025-Jun-14 5:41 
Questionnot running Pin
Rajat_Arora18-Mar-14 23:33
Rajat_Arora18-Mar-14 23:33 
AnswerRe: not running Pin
zenluiz15-Oct-14 7:14
zenluiz15-Oct-14 7:14 
QuestionError Comes Pin
vbheda28-Jan-14 1:18
vbheda28-Jan-14 1:18 
QuestionWebsocket URI Pin
Member 1050858815-Jan-14 2:21
Member 1050858815-Jan-14 2:21 
QuestionThis is not a chat application! Pin
Dewey4-Jan-14 23:59
Dewey4-Jan-14 23:59 
AnswerRe: This is not a chat application! Pin
Arash Javadi2-Apr-14 20:29
Arash Javadi2-Apr-14 20:29 
QuestionDoes your code work in any browser & version Pin
Tridip Bhattacharjee9-Jul-13 22:25
professionalTridip Bhattacharjee9-Jul-13 22:25 
AnswerRe: Does your code work in any browser & version Pin
HaBiX10-Jul-13 2:00
HaBiX10-Jul-13 2:00 
http://caniuse.com/websockets[^]
AnswerRe: Does your code work in any browser & version Pin
Florian Rappl11-Jul-13 20:46
professionalFlorian Rappl11-Jul-13 20:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.