WebSocket in .NET

Real-Time, Two-Way Communication Over TCP/IP

Roko Kovač
3 min readDec 2, 2023

Introduction

There are many techniques for achieving near-real-time communication using HTTP, such as Polling, Long Polling, Server-Sent Events, or even Webhooks.

All approaches share the same issue — they are limited to one-way communication.

In this article, we will explore WebSocket, a protocol built on top of TCP/IP that allows two-way, real-time communication and use it to implement a simple chat app in .NET 8.

WebSocket vs Server Sent Events

Just like in my previous articles, I will compare WebSocket with the closest alternative — SSE.

Similiarities

Both SSE and WebSockets:

  • use a single persistent TCP/IP connection
  • are supported in all modern browsers
  • allow real-time communication

Differences

Server Sent Events work with a simple HTTP request, which is limited by its Request — Response design to one-way communication.

WebSocket is a two-way (full duplex) real-time communication protocol built on top of TCP/IP. It uses an HTTP request to establish a connection (handshake), which is then upgraded to a WebSocket connection.

Unlike SSE, WebSocket also supports binary messages.

This makes it an excellent choice for cases where two-way communication is required, such as a chat app.

Establishing A WebSocket Connection

Implementing a WebSocket Server

Let’s build a simple WebSocket server in .NET 8.

If you just want the code, you can get it on my GitHub.

First, we will set up a web server and the required dependencies.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ChatService>();
var app = builder.Build();
app.UseWebSockets();

Then, we add a simple endpoint that will check for the required headers to determine if it’s a WebSocket request, and if so, accept it and pass it onto our ChatService.

app.MapGet("/", async (HttpContext context, ChatService chatService) =>
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await chatService.HandleWebSocketConnection(webSocket);
}
else
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync("Expected a WebSocket request");
}
});

In the ChatService, we will handle the WebSocket connection. It’s a singleton service that keeps track of all connected clients.

public class ChatService
{
private readonly List<WebSocket> _sockets = new();

public async Task HandleWebSocketConnection(WebSocket socket)
{
_sockets.Add(socket);
var buffer = new byte[1024 * 2];
while (socket.State == WebSocketState.Open)
{
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), default);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, default);
break;
}

foreach (var s in _sockets)
{
await s.SendAsync(buffer[..result.Count], WebSocketMessageType.Text, true, default);
}
}
_sockets.Remove(socket);
}
}

While the WebSocket is open, we await the next message. If it’s a Close message, we simply close the connection. If not, we read it and write it into an allocated buffer.

We then take a slice of the buffer that contains the message and send it to all connected clients.

To keep it simple, we don’t validate message type or message size, or serialize/deserialize to domain entities, which is something you would probably want to do in a real application.

Implementing a WebSocket Client

As it’s supported by all browsers, we will use HTML and JavaScript to build a client.

<div id="messages"></div>
<input id="chatbox" >
<script>
const socket = new WebSocket('ws://localhost:5007');

socket.onmessage = function (event) {
const messages = document.getElementById("messages");
messages.innerHTML += `<p>${event.data}</p>`;
};

document.getElementById("chatbox").addEventListener("keyup", function(event) {
if (event.key === "Enter") {
socket.send(event.target.value);
event.target.value = "";
}
});
</script>

This simple code opens up a WebSocket connection and displays something resembling a chat application.

A Simple Chat App

Conclusion

I have introduced you to the WebSocket protocol and shown you how to implement a simple WebSocket server in .NET 8

For a more advanced use case, check out my chat app.

If you’re interested in .NET topics, consider subscribing.

Any thoughts? Comments are welcome!

--

--