Langer Anruf oder ewiger Kanal: Wie C# Daten in Echtzeit ausgibt
\n\nStellen Sie sich vor: Sie schreiben einen Chat in C#. Oder einen Börsenterminal. Oder ein Benachrichtigungssystem. Der Kunde wartet auf Daten – und ist nicht bereit, lange zu warten. Früher behalfen sich Entwickler, wie sie konnten: Sie stellten Timer ein, riefen den Server alle 5 Sekunden auf, erzeugten unnötige Anfragen. Heute haben wir zwei zivilisierte Ansätze – Long Polling und WebSocket. Beide erlauben dem Server, Daten an den Kunden zu senden, ohne dessen explizite Anfrage. Aber sie funktionieren grundlegend unterschiedlich.
\n\nIn diesem Artikel analysieren wir, wie man beide Ansätze in C# (ASP.NET Core) implementiert, vergleichen sie hinsichtlich Geschwindigkeit, Last und Komplexität und verstehen, was Sie für Ihr Projekt wählen sollten. Los geht's.
\n\nWas ist Long Polling? (Und warum es keine Zauberei ist)
\n\nLong Polling ist eine Emulation von Echtzeit über gewöhnliches HTTP. Der Kunde sendet eine Anfrage an den Server, aber der Server antwortet nicht sofort. Er hält die Verbindung offen, bis ein neues Ereignis eintritt (oder ein Timeout abläuft). Sobald die Daten bereit sind – sendet der Server eine Antwort, der Kunde verarbeitet sie und öffnet sofort eine neue «lange» Anfrage.
\n\nDies ist ein cleverer Trick, der auf jedem HTTP-Server und in jedem Browser funktioniert. Aber er hat seinen Preis: Jede Verbindung hängt im Speicher des Servers, und wenn es Tausende von Kunden gibt – ist das bereits ein Problem.
\n\nBeispiel für Long Polling in C# (ASP.NET Core)
\n\nSchreiben wir einen einfachen Controller, der eine Benachrichtigungswarteschlange simuliert. Der Kunde ruft den Endpunkt auf, der Server wartet auf neue Daten (z.B. aus einem Kanal Channel<string>) und sendet sie.
using Microsoft.AspNetCore.Mvc;\nusing System.Threading.Channels;\n\n[ApiController]\n[Route("api/[controller]")]\npublic class NotificationsController : ControllerBase\n{\n private static readonly Channel<string> _channel = Channel.CreateUnbounded<string>();\n\n // Endpunkt zum Veröffentlichen einer Benachrichtigung (z.B. aus einem anderen Dienst)\n [HttpPost("publish")]\n public async Task<IActionResult> Publish([FromBody] string message)\n {\n await _channel.Writer.WriteAsync(message);\n return Ok("Benachrichtigung gesendet");\n }\n\n // Long Polling: Der Kunde wartet, bis eine neue Nachricht erscheint\n [HttpGet("long-poll")]\n public async Task<IActionResult> LongPoll(CancellationToken cancellationToken)\n {\n // Warte auf eine neue Nachricht; wenn nichts da ist – warte bis zu 30 Sekunden\n using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n cts.CancelAfter(TimeSpan.FromSeconds(30));\n\n try\n {\n var message = await _channel.Reader.ReadAsync(cts.Token);\n return Ok(new { data = message });\n }\n catch (OperationCanceledException)\n {\n // Timeout – leere Antwort zurückgeben, der Kunde wiederholt die Anfrage\n return Ok(new { data = (string?)null });\n }\n }\n}\n\n\nDer Kunde (JavaScript) sieht dann so aus:
\n\nasync function startLongPoll() {\n while (true) {\n const response = await fetch('/api/notifications/long-poll');\n const result = await response.json();\n if (result.data) {\n console.log('Neue Benachrichtigung:', result.data);\n }\n // Sofort einen neuen Poll starten\n }\n}\nstartLongPoll();\n\n\nAlles einfach. Aber es gibt einen Haken: Wenn der Server neu startet oder der Kunde die Verbindung verliert – gehen Daten verloren. Long Polling garantiert keine Zustellung.
\n\nWebSocket: Zweiseitiger Tunnel in C#
\n\nWebSocket ist ein vollwertiges Protokoll für die bidirektionale Kommunikation über TCP. Nach dem Handshake (einem gewöhnlichen HTTP GET mit Upgrade) kommunizieren Kunde und Server direkt, ohne den Overhead von HTTP-Headern. Der Server kann jederzeit eine Nachricht senden, und der Kunde erhält sie sofort.
\n\nIn ASP.NET Core ist WebSocket von Haus aus integriert. Es sind keine externen Bibliotheken erforderlich (