Real-time Communication with WebSocket Protocol in ASP.NET Core

Introduction

Creating a complete example of real-time communication using the WebSocket protocol in ASP.NET Core involves several steps. In this example, we will create a simple chat application where users can send and receive messages in real-time. This example assumes you have a basic understanding of ASP.NET Core and C#.

Step 1. Create a new ASP.NET Core project

First, create a new ASP.NET Core project using Visual Studio or the command line. You can choose the ASP.NET Core Web Application template and select the Empty template.

Step 2. Install WebSocket NuGet Package

In your project, you need to install Microsoft.AspNetCore.WebSockets NuGet package, which provides WebSocket support.

dotnet add package Microsoft.AspNetCore.WebSockets

Step 3. Create a WebSocket Middleware

In your Startup.cs file, configure WebSocket middleware in the Configure method.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using WebSocketChatApp.Middleware;

Author: Sardar Mudassar Ali Khan
namespace WebSocketChatApp
{
    public class Startup
    {
        // ... other configurations ...

        public void ConfigureServices(IServiceCollection services)
        {
            // ... other services ...

            services.AddWebSocketManager();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // ... other middleware ...

            app.UseWebSockets();
            app.MapWebSocketManager("/chat", app.ApplicationServices.GetService<ChatWebSocketHandler>());

            // ... other configurations ...
        }
    }
}

Step 4. Create a WebSocket Handler

Create a WebSocket handler class to manage WebSocket connections and messages. You can name it ChatWebSocketHandler.cs.

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

Author: Sardar Mudassar Ali Khan
namespace WebSocketChatApp.Middleware
{
    public class ChatWebSocketHandler
    {
        private readonly WebSocketConnectionManager _connectionManager;
        private readonly ILogger<ChatWebSocketHandler> _logger;

        public ChatWebSocketHandler(WebSocketConnectionManager connectionManager, ILogger<ChatWebSocketHandler> logger)
        {
            _connectionManager = connectionManager;
            _logger = logger;
        }

        public async Task HandleWebSocket(HttpContext context, WebSocket webSocket)
        {
            var socketId = _connectionManager.AddSocket(webSocket);

            _logger.LogInformation($"WebSocket connection established with ID {socketId}");

            while (webSocket.State == WebSocketState.Open)
            {
                var message = await ReceiveMessageAsync(webSocket);
                if (message != null)
                {
                    _logger.LogInformation($"Received message from ID {socketId}: {message}");
                    await BroadcastMessageAsync(message);
                }
            }

            _connectionManager.RemoveSocket(socketId);
            _logger.LogInformation($"WebSocket connection closed with ID {socketId}");
        }

        private async Task<string?> ReceiveMessageAsync(WebSocket webSocket)
        {
            var buffer = new byte[1024];
            var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

            if (result.CloseStatus.HasValue)
            {
                return null;
            }

            return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
        }

        private async Task BroadcastMessageAsync(string message)
        {
            foreach (var socket in _connectionManager.GetAllSockets())
            {
                if (socket.Value.State == WebSocketState.Open)
                {
                    await socket.Value.SendAsync(System.Text.Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, CancellationToken.None);
                }
            }
        }
    }
}

Step 5. Create WebSocket Connection Manager

Create a WebSocket connection manager to keep track of connected WebSocket clients. You can name it WebSocketConnectionManager.cs.

using System;
using System.Collections.Concurrent;
using System.Net.WebSockets;

Author: Sardar Mudassar Ali Khan
namespace WebSocketChatApp.Middleware
{
    public class WebSocketConnectionManager
    {
        private readonly ConcurrentDictionary<Guid, WebSocket> _sockets = new ConcurrentDictionary<Guid, WebSocket>();

        public WebSocket AddSocket(WebSocket socket)
        {
            var socketId = Guid.NewGuid();
            _sockets.TryAdd(socketId, socket);
            return socketId;
        }

        public WebSocket? GetSocket(Guid socketId)
        {
            _sockets.TryGetValue(socketId, out var socket);
            return socket;
        }

        public ConcurrentDictionary<Guid, WebSocket>.ValueCollection GetAllSockets()
        {
            return _sockets.Values;
        }

        public Guid? GetSocketId(WebSocket socket)
        {
            foreach (var (key, value) in _sockets)
            {
                if (value == socket)
                {
                    return key;
                }
            }
            return null;
        }

        public void RemoveSocket(Guid socketId)
        {
            _sockets.TryRemove(socketId, out _);
        }
    }
}

Step 6. Create WebSocket Endpoint

Create a WebSocket endpoint in your controller to handle WebSocket connections.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net.WebSockets;
using System.Threading.Tasks;
using WebSocketChatApp.Middleware;

Author: Sardar Mudassar Ali Khan
namespace WebSocketChatApp.Controllers
{
    [Route("api/[controller]")]
    public class ChatController : ControllerBase
    {
        private readonly ChatWebSocketHandler _webSocketHandler;

        public ChatController(ChatWebSocketHandler webSocketHandler)
        {
            _webSocketHandler = webSocketHandler;
        }

        [HttpGet]
        public async Task<IActionResult> Get()
        {
            if (HttpContext.WebSockets.IsWebSocketRequest)
            {
                var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
                await _webSocketHandler.HandleWebSocket(HttpContext, webSocket);
            }
            else
            {
                return BadRequest("WebSocket is not supported.");
            }

            return Ok();
        }
    }
}

Step 7. Create a Client-Side Application

Create a simple HTML page with JavaScript to connect to the WebSocket server and send/receive messages. Here's a basic example:

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Chat By Sardar Mudassar Ali Khan</title>
</head>
<body>
    <input type="text" id="messageInput" placeholder="Enter your message" />
    <button onclick="sendMessage()">Send</button>
    <div id="chat"></div>

    <script>
        const socket = new WebSocket("ws://localhost:5000/api/chat");

        socket.onopen = (event) => {
            console.log("WebSocket connection established.");
        };

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

        socket.onclose = (event) => {
            if (event.wasClean) {
                console.log(`WebSocket connection closed cleanly, code=${event.code}, reason=${event.reason}`);
            } else {
                console.error(`WebSocket connection died`);
            }
        };

        function sendMessage() {
            const messageInput = document.getElementById("messageInput");
            const message = messageInput.value;
            socket.send(message);
            messageInput.value = "";
        }
    </script>
</body>
</html>

Step 8. Run the Application

Build and run your ASP.NET Core application. Access the WebSocket chat page in your browser. You should be able to send and receive messages in real-time.

This example provides a basic implementation of a WebSocket chat application in ASP.NET Core. You can extend and customize it according.

Conclusion

This example provides a foundational structure for real-time communication in ASP.NET Core using WebSockets. You can expand upon this foundation to create more complex real-time applications, such as chat rooms, notifications, or collaborative editing tools, by adding features like authentication, user management, and message persistence.


Similar Articles