Server-Sent Events en C# : Le Web Réactif sans WebSocket

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi votre site ne « parle »-t-il pas encore à l'utilisateur en temps réel ?

\n\n

Imaginez : vous ouvrez un terminal boursier, et le taux du dollar se met à jour tout seul. Ou vous accédez à l'interface d'administration — et vous voyez le nombre d'utilisateurs inscrits augmenter sous vos yeux. Ou un chat où les messages arrivent sans « rafraîchissements » constants de la page.

\n\n

Avant, pour cela, il fallait soit mettre en place WebSocket (complexe, coûteux, pas toujours nécessaire), soit utiliser le long polling (un bricolage qui épuise la batterie du téléphone). Mais il existe une troisième voie — les Server-Sent Events en C#.

\n\n

Aujourd'hui, nous allons décortiquer une technologie qui permet au serveur de « frapper » lui-même à la porte du client et de transmettre des données. Sans code superflu, sans tonnes de JavaScript, sans maux de tête avec les serveurs proxy. Que du C#, que du costaud.

\n\n

Que sont les Server-Sent Events (SSE) et pourquoi ce n'est pas un « protocole pour les pauvres »

\n\n

Server-Sent Events (ou SSE) est un standard HTML5 qui permet au serveur d'envoyer des données en continu au client via une connexion HTTP ordinaire. Le client s'abonne aux événements, et le serveur écrit simplement dans Response.Body. C'est tout.

\n\n

La principale différence avec WebSocket : SSE est un canal unidirectionnel (serveur → client). Vous n'avez pas besoin d'envoyer des données en retour ? Parfait, SSE est fait pour vous. De plus :

\n\n
    \n
  • Fonctionne sur HTTP/1.1 et HTTP/2 standard
  • \n
  • Se reconnecte automatiquement en cas de coupure (intégré dans l'EventSource du navigateur)
  • \n
  • Ne nécessite pas de bibliothèques supplémentaires côté client (à part le JavaScript standard)
  • \n
  • Passe à travers tous les proxys et équilibreurs de charge (contrairement à WebSocket)
  • \n
\n\n

En pratique, SSE C# est utilisé pour :

\n
    \n
  • Les flux de notifications (notifications push directement dans le navigateur)
  • \n
  • La surveillance de serveurs (tableaux de bord avec métriques en direct)
  • \n
  • La diffusion de logs (par exemple, tail -f dans le navigateur)
  • \n
  • Le streaming de générations AI (distribution progressive des réponses des modèles de type ChatGPT)
  • \n
\n\n

Comment fonctionne SSE : le protocole en une ligne

\n\n

Tout ce qui est génial est simple. Le serveur envoie au client un flux de texte avec un format spécial :

\n\n
data: Bonjour le monde !\\n\\n\ndata: {"message": "Le JSON fonctionne aussi"}\\n\\n\nevent: customEvent\\n\ndata: Événement nommé\\n\\n
\n\n

Chaque message commence par data:, se termine par deux retours à la ligne. Vous pouvez spécifier event: pour un type d'événement personnalisé, id: pour un identifiant et retry: pour le délai de reconnexion.

\n\n

Le client en JavaScript s'abonne ainsi :

\n\n
const source = new EventSource("/api/stream");\nsource.onmessage = (event) => {\n    console.log("Reçu :", event.data);\n};\nsource.addEventListener("customEvent", (event) => {\n    console.log("Événement personnalisé :", event.data);\n});
\n\n

Et cela fonctionne dans tous les navigateurs modernes. Pas de paquets npm, pas de polyfills WebSocket.

\n\n

Server-Sent Events en C# : Implémentation sur ASP.NET Core

\n\n

Écrivons enfin le code. La façon la plus simple d'organiser les SSE en C# est de créer un point de terminaison (endpoint) dans ASP.NET Core qui ne termine pas la réponse, mais y écrit par morceaux.

\n\n

Endpoint SSE de base

\n\n
using 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            // Format SSE : data: ... \\n\\n\n            await Response.WriteAsync($"data: Message #{i}\\n\\n",                

Blogs

Book Recommendations