¿Por qué su sitio web todavía no "habla" con el usuario en tiempo real?
\n\nImagine: abre un terminal de bolsa y el tipo de cambio del dólar se actualiza solo. O ingresa al panel de administración y ve cómo, ante sus ojos, aumenta la cantidad de usuarios registrados. O un chat donde los mensajes llegan sin constantes "actualizaciones" de la página.
\n\nAntes, para esto había que instalar WebSocket (complejo, costoso, no siempre necesario) o usar long polling (un parche que agota la batería del teléfono). Pero hay un tercer camino: Server-Sent Events en C#.
\n\nHoy analizaremos la tecnología que permite al servidor "llamar" al cliente de forma autónoma y transmitir datos. Sin código innecesario, sin toneladas de JavaScript, sin dolores de cabeza con servidores proxy. Solo C#, solo pura esencia.
\n\n¿Qué son los Server-Sent Events (SSE) y por qué no son un "protocolo para pobres"?
\n\nServer-Sent Events (o SSE) es un estándar HTML5 que permite al servidor enviar datos en streaming al cliente a través de una conexión HTTP normal. El cliente se suscribe a los eventos y el servidor simplemente escribe en Response.Body. Eso es todo.
\n\nLa principal diferencia con WebSocket: SSE es un canal unidireccional (servidor → cliente). ¿No necesita enviar datos de vuelta? Perfecto, SSE es su elección. Además:
\n\n- \n
- Funciona sobre HTTP/1.1 y HTTP/2 estándar \n
- Se reconecta automáticamente en caso de interrupción (integrado en el
EventSourcedel navegador) \n - No requiere bibliotecas adicionales en el cliente (excepto JavaScript estándar) \n
- Atraviesa cualquier proxy y balanceador de carga (a diferencia de WebSocket) \n
En la práctica, SSE C# se utiliza para:
\n- \n
- Canales de notificaciones (notificaciones push directamente al navegador) \n
- Monitoreo de servidores (paneles con métricas en vivo) \n
- Transmisión de registros (por ejemplo, tail -f en el navegador) \n
- Streaming de generaciones de IA (entrega gradual de respuestas de modelos tipo ChatGPT) \n
Cómo funciona SSE: el protocolo en una línea
\n\nTodo lo genial es simple. El servidor envía al cliente un flujo de texto con un formato especial:
\n\ndata: ¡Hola, mundo!\\n\\n\ndata: {"message": "JSON también funciona"}\\n\\n\nevent: customEvent\\n\ndata: Evento con nombre\\n\\n\n\nCada mensaje comienza con data:, termina con dos saltos de línea. Se puede especificar event: para un tipo de evento personalizado, id: para un identificador y retry: para el tiempo de espera de reconexión.
El cliente en JavaScript se suscribe así:
\n\nconst source = new EventSource("/api/stream");\nsource.onmessage = (event) => {\n console.log("Recibido:", event.data);\n};\nsource.addEventListener("customEvent", (event) => {\n console.log("Evento personalizado:", event.data);\n});\n\nY esto funciona en todos los navegadores modernos. Sin paquetes npm, sin polyfills de WebSocket.
\n\nServer-Sent Events en C#: Implementación en ASP.NET Core
\n\nFinalmente, escribamos el código. La forma más sencilla de organizar SSE en C# es un endpoint en ASP.NET Core que no finaliza la respuesta, sino que escribe en ella por 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: Mensaje #{i}\\n\\n",