How to use Websockets with Asp.net core - an example on how to push messages to a website

I finally decided that it was time to give websockets a try. They have been around for over a decade, but I just had not found the time to play around with them. Websockets are a great way to keep a connection alive and push messages back and forth between server and client. In this article I show you how you can push messages to a client. I am using asp.net core as a backend and I have created a light frontend to test this with. You can find a link to a github repository with all the code at the end of the article. But the code bits on this page should be good enough for you to recreate the examples.

The backend

In this post I am using asp.net core. My Startup.cs class look like the following:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles();
    app.UseWebSockets();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Page}/{action=Index}/{id?}");
    });
}

What is the key takeaway here? Well first of all I enable staticfiles. This is to be able to serve some resources (javascript) later. This is not needed if you have no frontend for your application. Then the important part comes - app.UseWebSockets();. This enables the application to use websockets which is what this post is all about. The rest is the usual enabling of MVC and configuration of routes.

Next up I am creating my StreamController, which will be handling the websocket request:

[Route("api/[controller]")]
public class StreamController : Controller
{
    // GET api/values
    [HttpGet]
    public async Task Get()
    {
        var context = ControllerContext.HttpContext;
        var isSocketRequest = context.WebSockets.IsWebSocketRequest;

        if (isSocketRequest)
        {
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await GetMessages(context, webSocket);
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }

    private async Task GetMessages(HttpContext context, WebSocket webSocket)
    {
        var messages = new[]
        {
            "Message1",
            "Message2",
            "Message3",
            "Message4",
            "Message5"
        };
        
        foreach (var message in messages)
        {
            var bytes = Encoding.ASCII.GetBytes(message);
            var arraySegment = new ArraySegment<byte>(bytes);
            await webSocket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
            Thread.Sleep(2000); //sleeping so that we can see several messages are sent
        }

        await webSocket.SendAsync(new ArraySegment<byte>(null), WebSocketMessageType.Binary, false, CancellationToken.None);
    }
}

In the above I have created a method Get() within my StreamController. You will notice that this is invoked with a simple HttpGet and returns nothing (Task). But it does in fact send something back to the client, but this happens deeper in the method. The first thing that happens within the Get() method is the upgrade of the connection - which is done by invoking the following: await context.WebSockets.AcceptWebSocketAsync();. If the connection is successfully upgraded, we move on to execute where the interesting stuff is - the GetMessages() method. Here the interesting part is the following:

await webSocket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);

Here I send a message to the client. It was that simple. The list of messages and the Thread.Sleep() are only there to have something to send, and delay it - so that i could see the messages were received separately. This you would replace with whatever you wish to send to your client.

That is all there is to the backend. This will stream my 5 messages to the frontend, with a 2 seconds delay in between them. Then close the connection.

The frontend

In order to have a UI to show this, I made a small and simple HTML page named Index.cshtml, which looks like the following:

<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Page</title>
    </head>
    <body>
        <h1>Stream to me</h1>
        <ul id="StreamToMe"></ul>

        <script src="~/js/stream.js"></script>
    </body>
</html>

It is a very simple HTML page. The only important part is that I have created an unordered list element (ul). This is what I intend to populate with the messages from the backend. The other important part of the page is the script stream.js. Which is a simple javascript that creates the websocket connection, as seen below:

(function() {
    var getWebSocketMessages = function(onMessageReceived)
    {
        var url = `ws://${location.host}/api/stream`
        console.log('url is: ' + url);

        var webSocket = new WebSocket(url);

        webSocket.onmessage = onMessageReceived;
    };

    var ulElement = document.getElementById('StreamToMe');

    getWebSocketMessages(function (message) {
        ulElement.innerHTML = ulElement.innerHTML += `<li>${message.data}</li>`
    });
}());

Here I first setup the URL for my asp.net application pointing to the controller and action i created earlier. Notice that it uses the WS protocol, not HTTP. I then create a websocket object and inject the URL and add an onMessageReceived handler to it. That is basically it, whenever a message is pushed from the backend it is appended to the ul element that I made.

The Result

The combination of the above results in me "streaming" several messages to the frontend. In the below image I have waited 6 seconds, and have received a total of 3 messages:

Websocket streaming of 3 out of 5 messages

That concludes this very simple example on how to do websocket communication in asp.net core. Below I have a screenshot of the network tab, where you can see that the websocket protocol was indeed used:

Websocket traffic shown in the network tab of chrome

All the code from this article can be found at github. You can fetch the code from there or just explore the whole solution.

This was my post on how to implement websockets with asp.net core. My web development skills are likely rusty as I have not done proper web development for over 2 years. If you have any tips or something that you would have done differently please let me know in the comments down below. Any other feedback is deeply appreciated as well :)