Introdução: Por que o WebSocket é o padrão para aplicações em tempo real?
As aplicações web modernas exigem reação instantânea às ações do usuário. Seja um chat online, terminal de ações, jogo multijogador ou sistema de monitoramento — atrasos na transmissão de dados são inaceitáveis. O protocolo HTTP tradicional, que opera no princípio de "requisição-resposta", é ineficiente para esses cenários: o cliente precisa consultar constantemente o servidor (polling), criando carga excessiva.
O WebSocket vem em socorro — um protocolo que fornece uma conexão bidirecional contínua entre cliente e servidor. Neste artigo, vamos explorar como criar aplicações em tempo real em C# (.NET) usando WebSocket, desde um simples servidor eco até um chat completo. Você aprenderá como o protocolo funciona, quais ferramentas a plataforma .NET oferece e como evitar erros comuns.
Fundamentos do WebSocket no .NET: Lado do servidor
A plataforma .NET oferece suporte nativo a WebSocket através do namespace System.Net.WebSockets. Vamos criar um servidor baseado em ASP.NET Core.
1. Configuração do Middleware para WebSocket
Primeiro, é necessário adicionar suporte a WebSocket no pipeline de processamento de requisições. No arquivo Program.cs:
var builder = WebApplication.CreateBuilder(args);var app = builder.Build();
app.UseWebSockets(); // Ativa suporte a WebSocket
app.Map("/ws", async (HttpContext context) =>{ if (context.WebSockets.IsWebSocketRequest) { using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); await Echo(webSocket); } else { context.Response.StatusCode = 400; }});
app.Run("http://localhost:5000");
async Task Echo(WebSocket webSocket){ var buffer = new byte[1024 * 4]; var receiveResult = await webSocket.ReceiveAsync( new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue) { // Envia os dados recebidos de volta ao cliente (eco) await webSocket.SendAsync( new ArraySegment<byte>(buffer, 0, receiveResult.Count), receiveResult.MessageType, receiveResult.EndOfMessage, CancellationToken.None);
receiveResult = await webSocket.ReceiveAsync( new ArraySegment<byte>(buffer), CancellationToken.None); }
await webSocket.CloseAsync( receiveResult.CloseStatus.Value, receiveResult.CloseStatusDescription, CancellationToken.None);}Este código cria um servidor eco: tudo que o cliente envia é retornado. Observe o uso de async/await — o trabalho com WebSocket é sempre assíncrono.
2. Gerenciamento de múltiplas conexões
Em uma aplicação real, é necessário gerenciar várias conexões. Vamos criar um gerenciador de conexões simples:
public class WebSocketConnectionManager{ private readonly ConcurrentDictionary<string, WebSocket> _connections = new();
public string AddConnection(WebSocket socket) { var id = Guid.NewGuid().ToString(); _connections.TryAdd(id, socket); return id; }
public async Task BroadcastMessageAsync(string message) { var tasks = _connections.Values.Select(async socket => { if (socket.State == WebSocketState.Open) { var bytes = Encoding.UTF8.GetBytes(message); await socket.SendAsync( new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, CancellationToken.None); } }); await Task.WhenAll(tasks); }}Esta classe permite armazenar todas as conexões ativas e transmitir mensagens