Por que seu site ainda não "conversa" com o usuário em tempo real?
\n\nImagine: você abre um terminal de ações e a cotação do dólar se atualiza sozinha. Ou entra no painel de administração e vê, diante dos seus olhos, o número de usuários registrados aumentando. Ou um chat onde as mensagens chegam sem constantes "atualizações" de página.
\n\nAntes, para isso, era necessário ou usar WebSocket (complexo, caro, nem sempre necessário) ou usar long polling (gambiarra que drena a bateria do celular). Mas existe um terceiro caminho — Server-Sent Events em C#.
\n\nHoje vamos analisar a tecnologia que permite ao servidor "bater na porta" do cliente e transmitir dados de forma autônoma. Sem código desnecessário, sem toneladas de JavaScript, sem dores de cabeça com servidores proxy. Apenas C#, apenas hardcore.
\n\nO que são Server-Sent Events (SSE) e por que não é um "protocolo para pobres"
\n\nServer-Sent Events (ou SSE) é um padrão HTML5 que permite ao servidor enviar dados em streaming para o cliente através de uma conexão HTTP comum. O cliente se inscreve nos eventos e o servidor simplesmente escreve no Response.Body. Só isso.
\n\nA principal diferença do WebSocket: SSE é um canal unidirecional (servidor → cliente). Não precisa enviar dados de volta? Ótimo, SSE é sua escolha. Além disso:
\n\n- \n
- Funciona sobre HTTP/1.1 e HTTP/2 comuns \n
- Reconecta automaticamente em caso de queda (embutido no
EventSourcedo navegador) \n - Não requer bibliotecas adicionais no cliente (além do JavaScript padrão) \n
- Atravessa qualquer proxy e balanceador de carga (ao contrário do WebSocket) \n
Na prática, SSE C# é usado para:
\n- \n
- Feed de notificações (notificações push diretamente no navegador) \n
- Monitoramento de servidores (painéis com métricas ao vivo) \n
- Transmissão de logs (ex: tail -f no navegador) \n
- Streaming de gerações de IA (resposta gradual de modelos como ChatGPT) \n
Como o SSE funciona: protocolo de uma linha
\n\nTudo que é genial é simples. O servidor envia ao cliente um fluxo de texto com um formato especial:
\n\ndata: Olá, mundo!\\n\\n\ndata: {"message": "JSON também funciona"}\\n\\n\nevent: customEvent\\n\ndata: Evento com nome\\n\\n\n\nCada mensagem começa com data:, termina com duas quebras de linha. Pode-se especificar event: para um tipo de evento personalizado, id: para um identificador e retry: para o tempo limite de reconexão.
O cliente em JavaScript se inscreve assim:
\n\nconst source = new EventSource("/api/stream");\nsource.onmessage = (event) => {\n console.log("Recebido:", event.data);\n};\nsource.addEventListener("customEvent", (event) => {\n console.log("Evento personalizado:", event.data);\n});\n\nE isso funciona em todos os navegadores modernos. Sem pacotes npm, sem polyfills de WebSocket.
\n\nServer-Sent Events em C#: Implementação no ASP.NET Core
\n\nVamos finalmente escrever o código. A maneira mais simples de organizar SSE em C# é um endpoint no ASP.NET Core que não finaliza a resposta, mas escreve nela em partes.
\n\nEndpoint SSE básico
\n\nusing Microsoft.AspNetCore.Mvc;\n\n[ApiController]\n[Route("api")]\npublic class StreamController : ControllerBase\n{\n [HttpGet("stream")]\n public async Task Get(CancellationToken cancellationToken)\n {\n Response.Headers.Append("Content-Type", "text/event-stream");\n Response.Headers.Append("Cache-Control", "no-cache");\n Response.Headers.Append("Connection", "keep-alive");\n\n for (int i = 0; i < 10; i++)\n {\n if (cancellationToken.IsCancellationRequested)\n break;\n\n // Formato SSE: data: ... \\n\\n\n await Response.WriteAsync($"data: Mensagem #{i}\\n\\n",