SignalR in ASP.NET Core 2026: Echtzeitkommunikation, Hubs und Interview-Fragen
SignalR für Echtzeit-Webanwendungen in ASP.NET Core beherrschen. Hubs, Gruppen, Skalierung mit Redis und typische Interview-Fragen.

SignalR ermöglicht bidirektionale Echtzeitkommunikation zwischen Servern und Clients in ASP.NET Core-Anwendungen. Im Gegensatz zu traditionellen HTTP-Request-Response-Mustern unterhält SignalR persistente Verbindungen, die es Servern erlauben, Updates sofort an Clients zu senden – unverzichtbar für Chat-Anwendungen, Live-Dashboards, kollaboratives Bearbeiten und Echtzeit-Benachrichtigungen.
SignalR wählt automatisch den besten verfügbaren Transport: zuerst WebSockets, dann Server-Sent Events, dann Long Polling. Dieser Fallback-Mechanismus gewährleistet Kompatibilität über alle Browser und Netzwerkkonfigurationen hinweg, ohne dass Codeänderungen erforderlich sind.
Wie SignalR Hubs die Server-Client-Kommunikation ermöglichen
Ein Hub fungiert als High-Level-Pipeline, die Methodenaufrufe zwischen Clients und Servern verarbeitet. Clients rufen Methoden auf dem Hub auf, und der Hub kann Methoden auf verbundenen Clients aufrufen. Diese Abstraktion eliminiert die Komplexität der manuellen WebSocket-Verbindungsverwaltung.
Das folgende Beispiel demonstriert einen einfachen Chat-Hub, der Nachrichten an alle verbundenen Clients sendet:
using Microsoft.AspNetCore.SignalR;
public class ChatHub : Hub
{
// Called when a client sends a message
public async Task SendMessage(string user, string message)
{
// Broadcast to ALL connected clients
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
// Called automatically when a client connects
public override async Task OnConnectedAsync()
{
await Clients.Caller.SendAsync("Connected", Context.ConnectionId);
await base.OnConnectedAsync();
}
// Called automatically when a client disconnects
public override async Task OnDisconnectedAsync(Exception? exception)
{
// Clean up resources, notify other users, etc.
await base.OnDisconnectedAsync(exception);
}
}Die Clients-Eigenschaft bietet Zugriff auf alle verbundenen Clients über verschiedene Targeting-Optionen: All, Caller, Others, Group und User.
Konfiguration von SignalR in ASP.NET Core 9
Die SignalR-Registrierung in ASP.NET Core 9 folgt dem Standard-Middleware-Muster. Die folgende Konfiguration aktiviert JSON- und MessagePack-Protokolle mit benutzerdefinierten Puffergrößen:
var builder = WebApplication.CreateBuilder(args);
// Add SignalR services with configuration
builder.Services.AddSignalR(options =>
{
options.EnableDetailedErrors = builder.Environment.IsDevelopment();
options.MaximumReceiveMessageSize = 64 * 1024; // 64 KB
options.StreamBufferCapacity = 10;
options.KeepAliveInterval = TimeSpan.FromSeconds(15);
options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
})
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = null; // PascalCase
});
var app = builder.Build();
// Map the hub endpoint
app.MapHub<ChatHub>("/chathub");
app.Run();Die Einstellungen KeepAliveInterval und ClientTimeoutInterval steuern die Überwachung des Verbindungszustands. Clients, die innerhalb des Timeout-Zeitraums nicht antworten, gelten als getrennt.
Verwaltung von Gruppen für gezielte Nachrichtenübermittlung
Gruppen bieten einen Mechanismus zur Organisation von Verbindungen und zum Senden von Nachrichten an Teilmengen von Clients. Ein typischer Anwendungsfall umfasst Chatrooms, in denen Benutzer bestimmten Räumen beitreten und nur Nachrichten aus diesen Räumen erhalten.
public class GroupChatHub : Hub
{
// Add the current connection to a group
public async Task JoinRoom(string roomName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, roomName);
// Notify the group that someone joined
await Clients.Group(roomName).SendAsync(
"UserJoined",
Context.User?.Identity?.Name ?? "Anonymous"
);
}
// Remove the current connection from a group
public async Task LeaveRoom(string roomName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomName);
await Clients.Group(roomName).SendAsync(
"UserLeft",
Context.User?.Identity?.Name ?? "Anonymous"
);
}
// Send a message to a specific group only
public async Task SendToRoom(string roomName, string message)
{
await Clients.Group(roomName).SendAsync(
"ReceiveMessage",
Context.User?.Identity?.Name,
message
);
}
}Die Gruppenmitgliedschaft ist an Verbindungen gebunden, nicht an Benutzer. Wenn ein Benutzer sich neu verbindet, muss er seinen Gruppen erneut beitreten. Für persistente Gruppenmitgliedschaft sollten Gruppenassoziationen in einer Datenbank gespeichert und automatisch in OnConnectedAsync wiederhergestellt werden.
Gruppen existieren nur im Speicher und werden nicht über Server-Neustarts oder in skalierten Szenarien ohne Backplane persistiert. Für Produktions-Deployments mit mehreren Servern sollte Redis oder Azure SignalR Service als Backplane verwendet werden.
Absicherung von SignalR-Verbindungen mit Authentifizierung
SignalR integriert sich mit der ASP.NET Core-Authentifizierung. Das [Authorize]-Attribut beschränkt den Hub-Zugriff auf authentifizierte Benutzer, und Context.User bietet Zugriff auf die Claims des authentifizierten Benutzers.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
[Authorize] // Require authentication for the entire hub
public class SecureHub : Hub
{
// Access user claims through Context.User
public async Task SendPrivateMessage(string recipientUserId, string message)
{
var senderName = Context.User?.Identity?.Name
?? throw new HubException("User not authenticated");
// Send to a specific user (all their connections)
await Clients.User(recipientUserId).SendAsync(
"PrivateMessage",
senderName,
message
);
}
[Authorize(Roles = "Admin")] // Role-based authorization on method
public async Task BroadcastAnnouncement(string announcement)
{
await Clients.All.SendAsync("Announcement", announcement);
}
}Für WebSocket-Verbindungen müssen Authentifizierungstoken über Query-String übergeben werden, da WebSockets keine benutzerdefinierten Header unterstützen. Der JavaScript-Client wird so konfiguriert, dass er das Token einschließt:
import * as signalR from "@microsoft/signalr";
const connection = new signalR.HubConnectionBuilder()
.withUrl("/securehub", {
accessTokenFactory: () => localStorage.getItem("authToken") || ""
})
.withAutomaticReconnect()
.build();
await connection.start();Auf dem Server wird die JWT-Authentifizierung so konfiguriert, dass das Token aus dem Query-String gelesen wird:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// Read token from query string for SignalR
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
path.StartsWithSegments("/securehub"))
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});Bereit für deine .NET-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Skalierung von SignalR mit Redis Backplane
In einer lastverteilten Umgebung können Clients mit verschiedenen Server-Instanzen verbunden sein. Ohne Backplane erreichen Nachrichten, die von einem Server gesendet werden, nur die mit diesem Server verbundenen Clients. Redis dient als Backplane, um Nachrichten über alle Server-Instanzen zu synchronisieren.
builder.Services.AddSignalR()
.AddStackExchangeRedis(options =>
{
options.Configuration = builder.Configuration
.GetConnectionString("Redis");
// Optional: configure Redis-specific options
options.Configuration.ChannelPrefix =
RedisChannel.Literal("MyApp_SignalR_");
});Das Redis-Backplane veröffentlicht alle SignalR-Nachrichten auf Redis-Kanälen. Jede Server-Instanz abonniert diese Kanäle und liefert Nachrichten an ihre lokalen Clients. Dieser Ansatz fügt minimale Latenz hinzu (typischerweise 1-2ms) und ermöglicht gleichzeitig horizontale Skalierung.
Für Enterprise-Deployments bietet Azure SignalR Service eine verwaltete Alternative, die Skalierung, Verbindungsverwaltung und Verfügbarkeit automatisch handhabt.
Stark typisierte Hubs für Compile-Time-Sicherheit
Stark typisierte Hubs ersetzen Magic Strings durch Interface-Methoden und ermöglichen die Compile-Time-Verifizierung von Client-Methodenaufrufen:
public interface INotificationClient
{
Task ReceiveNotification(string title, string message, string severity);
Task UpdateProgress(int percentage);
Task TaskCompleted(Guid taskId, bool success);
}
// NotificationHub.cs
public class NotificationHub : Hub<INotificationClient>
{
public async Task NotifyAll(string title, string message)
{
// Compile-time checking - no magic strings
await Clients.All.ReceiveNotification(title, message, "info");
}
public async Task ReportProgress(string groupName, int percentage)
{
// IDE autocomplete works here
await Clients.Group(groupName).UpdateProgress(percentage);
}
}Refactoring wird sicherer, da das Umbenennen einer Methode im Interface sofort alle Aufrufstellen anzeigt, die aktualisiert werden müssen.
Streaming von Daten mit SignalR Channels
SignalR unterstützt Streaming für Szenarien, in denen Daten inkrementell produziert werden, wie Fortschritts-Updates, Log-Tailing oder Echtzeit-Sensordaten. Sowohl Server-zu-Client- als auch Client-zu-Server-Streaming werden unterstützt.
public class StreamingHub : Hub
{
// Server-to-client streaming with IAsyncEnumerable
public async IAsyncEnumerable<StockPrice> StreamStockPrices(
string[] symbols,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
var random = new Random();
while (!cancellationToken.IsCancellationRequested)
{
foreach (var symbol in symbols)
{
yield return new StockPrice
{
Symbol = symbol,
Price = random.NextDouble() * 1000,
Timestamp = DateTime.UtcNow
};
}
await Task.Delay(1000, cancellationToken);
}
}
// Client-to-server streaming
public async Task UploadStream(IAsyncEnumerable<LogEntry> stream)
{
await foreach (var entry in stream)
{
// Process each log entry as it arrives
await ProcessLogEntry(entry);
}
}
}
public record StockPrice(string Symbol, double Price, DateTime Timestamp);
public record LogEntry(string Level, string Message, DateTime Timestamp);Der JavaScript-Client konsumiert den Stream mit einem asynchronen Iterator:
const stream = connection.stream("StreamStockPrices", ["AAPL", "MSFT"]);
stream.subscribe({
next: (price) => console.log(`${price.symbol}: $${price.price}`),
error: (err) => console.error(err),
complete: () => console.log("Stream completed")
});Häufige SignalR Interview-Fragen
Technische Interviews behandeln häufig die SignalR-Architektur und praxisnahe Szenarien. Die folgenden Fragen erscheinen regelmäßig in .NET Interview-Sessions:
Erklären Sie den Transport-Aushandlungsprozess: SignalR versucht zuerst WebSockets, fällt dann auf Server-Sent Events zurück und dann auf Long Polling. Verstehen Sie, wann jeder Transport verwendet wird und welche Einschränkungen er hat.
F: Wie handhabt SignalR den Verbindungszustand, wenn ein Client vorübergehend die Verbindung verliert?
SignalR behält den Verbindungszustand auf dem Server für einen konfigurierbaren Zeitraum bei. Bei aktivierter automatischer Wiederverbindung versucht der Client, sich mit derselben Verbindungs-ID wieder zu verbinden. Bei Erfolg wird die Verbindung fortgesetzt, ohne dass Gruppenmitgliedschaften verloren gehen. Wenn die Trennung das Timeout überschreitet, wird eine neue Verbindung aufgebaut und der Client muss den Gruppen erneut beitreten.
F: Was ist der Unterschied zwischen Clients.User() und Clients.Client()?
Clients.User(userId) zielt auf alle Verbindungen eines bestimmten authentifizierten Benutzers ab – nützlich, wenn ein Benutzer mehrere Browser-Tabs geöffnet hat. Clients.Client(connectionId) zielt auf eine einzelne spezifische Verbindung ab. Benutzerbasiertes Targeting erfordert Authentifizierung und verwendet IUserIdProvider, um Verbindungen Benutzer-IDs zuzuordnen.
F: Wie würde man Präsenzerkennung implementieren (anzeigen, wer online ist)?
Verbindungen werden in OnConnectedAsync und OnDisconnectedAsync verfolgt. Benutzer-zu-Verbindungs-Mappings werden in einem Concurrent Dictionary oder verteilten Cache gespeichert. Für skalierte Deployments sollte ein gemeinsamer Speicher wie Redis verwendet werden. Präsenz-Updates werden an relevante Gruppen gesendet, wenn Benutzer sich verbinden oder trennen.
F: Erklären Sie den Zweck eines SignalR-Backplanes.
Ein Backplane synchronisiert Nachrichten über mehrere Server-Instanzen in einer lastverteilten Umgebung. Ohne Backplane erreichen Nachrichten, die von Server A gesendet werden, nur die mit Server A verbundenen Clients. Redis und Azure SignalR Service sind gängige Backplane-Optionen. Das Backplane veröffentlicht Nachrichten auf einem gemeinsamen Kanal, den alle Server abonnieren.
Strategien zur Performance-Optimierung
Die SignalR-Performance hängt von Nachrichtengröße, Frequenz und Verbindungsanzahl ab. Die ASP.NET Core Performance Best Practices-Dokumentation bietet detaillierte Benchmarks.
- MessagePack-Protokoll verwenden für binäre Serialisierung – reduziert die Payload-Größe um 30-50% im Vergleich zu JSON
- Nachrichten bündeln, wenn möglich, anstatt viele kleine Nachrichten zu senden
- Gruppengrößen begrenzen auf Tausende von Mitgliedern; für größere Zielgruppen sollten Pub/Sub-Muster in Betracht gezogen werden
- Kompression aktivieren für textlastige Payloads
- Angemessene Timeouts setzen, um Ressourcen von veralteten Verbindungen zeitnah freizugeben
// MessagePack configuration for smaller payloads
builder.Services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.SerializerOptions =
MessagePackSerializerOptions.Standard
.WithCompression(MessagePackCompression.Lz4Block);
});Fazit
- SignalR abstrahiert die Transport-Auswahl (WebSockets, SSE, Long Polling) und bietet ein konsistentes Programmiermodell für Echtzeitkommunikation
- Hubs zentralisieren die Verbindungsverwaltung; stark typisierte Hubs fügen Compile-Time-Sicherheit für Client-Methodenaufrufe hinzu
- Gruppen ermöglichen gezielte Nachrichtenübermittlung an Teilmengen von Verbindungen – Gruppen müssen nach Wiederverbindung erneut beigetreten werden
- Authentifizierung integriert sich mit ASP.NET Core Identity; Token werden über Query-String für WebSocket-Verbindungen übergeben
- Horizontale Skalierung erfolgt mit Redis-Backplane oder Azure SignalR Service zur Synchronisierung von Nachrichten über Server-Instanzen
- Streaming unterstützt inkrementelle Datenübermittlung mit
IAsyncEnumerablesowohl für Server-zu-Client- als auch Client-zu-Server-Szenarien
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.

Geschrieben von
Anthony Fillion-MailletFullstack-Entwickler, Gründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 12. August 2026
Teilen
Verwandte Artikel

ASP.NET Core Minimal APIs 2026: Architektur, Performance und Interview-Fragen
Minimal APIs in ASP.NET Core bieten eine schlanke Alternative zu MVC-Controllern mit weniger Boilerplate-Code, Native AOT-Unterstützung und optimierter Performance für Microservices und Serverless-Deployments.

.NET 10 im Jahr 2026: Neue Features, Native AOT und Interviewfragen fuer Entwickler
.NET 10 als LTS-Version bringt produktionsreife Native-AOT-Kompilierung, C# 14 mit Extension Members und dem field-Keyword, dateibasierte Anwendungen und benannte Abfragefilter in EF Core 10.

.NET MAUI 2026: Plattformübergreifende Entwicklung und Fragen für Vorstellungsgespräche
.NET MAUI Tutorial für 2026: Plattformübergreifende Apps mit .NET 10, Handlers, MVVM, HybridWebView entwickeln. Mit den wichtigsten Interviewfragen und Antworten.