ASP.NET Core SignalR Interview Questions for Senior .NET Developers (2026)

Search for a command to run...

No comments yet. Be the first to comment.
Most of the .NET conversation about the Model Context Protocol is about building servers: expose your API as MCP tools, point Claude or VS Code at it, done. That is the half that gets written about. T

The first RAG system I shipped answered beautifully about concepts and failed completely on part numbers. Ask it "how do I reset a stuck deployment" and it nailed the answer. Ask it "what does error P

AutoMapper has been the default object mapper in .NET for over a decade, and for most of that time nobody thought about it. Version 15.0.0 changed that. It ships under a dual license now, with a free

You built the pipeline. Documents are chunked, embedded, and sitting in a vector store. Retrieval returns results. And your RAG answers still hallucinate in .NET, confidently telling users about a stu

You upgraded a working API to .NET 10, hit build, and Swashbuckle fell apart. Missing namespaces, OpenApiSchema refusing to compile, AddSecurityRequirement complaining about a delegate it never wanted

Coding Droplets
304 posts
Coding Droplets is your go-to resource for .NET and ASP.NET Core development. Whether you're just starting out or building production systems, you'll find practical guides, real-world patterns, and clear explanations that actually make sense.
From beginner-friendly tutorials to advanced architecture decisions. We publish fresh .NET content every day to help you grow at every stage of your career.
ASP.NET Core SignalR is one of those topics that separates candidates who have built real-time features in production from those who have only read the docs. The questions interviewers ask about SignalR go well beyond "what is a Hub" — they probe your understanding of transport negotiation, connection lifecycle management, scaling across server instances, group messaging, and the trade-offs between SignalR and alternative real-time technologies. If you are preparing for a senior .NET role where real-time communication is part of the architecture, this guide covers the full range of questions you are likely to encounter. The complete working patterns — with annotated source code for production-grade SignalR scenarios — are available on Patreon, ready to run and adapt for your own projects.
If you want to see how ASP.NET Core SignalR has evolved recently, the What's New in ASP.NET Core 10 SignalR article is a good companion — it covers the specific improvements in .NET 10 that are increasingly showing up in 2026 interviews.
The questions below are grouped by difficulty: Basic → Intermediate → Advanced. Each question includes the key points a strong candidate is expected to cover.
ASP.NET Core SignalR is a library that simplifies adding real-time web functionality to applications. It enables server-to-client push communication — meaning the server can send data to connected clients at any time, without clients polling for it.
You should reach for SignalR when your application requires live push notifications, collaborative editing, real-time dashboards, chat functionality, or any scenario where server-initiated updates are necessary. If the communication pattern is strictly request/response, SignalR is unnecessary overhead and a standard REST or gRPC endpoint is the right tool.
A Hub is the central abstraction in ASP.NET Core SignalR. It is the server-side class clients connect to and through which all communication flows. Hubs expose methods that clients can call (similar to RPC), and they provide a built-in proxy through which the server can invoke methods on connected clients.
A strong answer includes: Hub is transient per-invocation, so you should not store state in Hub instance fields. Use IHubContext<T> when you need to send messages from outside the Hub class (e.g., from a controller or background service).
SignalR supports three transports, selected via negotiation in order of preference:
The negotiation process is automatic. SignalR will select the best transport supported by both the client and the server environment. You can restrict or force specific transports if required.
These are built-in properties on the Hub base class that provide different targeting scopes for sending messages:
Clients.All — sends a message to every connected clientClients.Caller — sends a message only to the client that invoked the current Hub methodClients.Others — sends to all connected clients except the callerClients.Client(connectionId) — sends to a specific client by its connection IDClients.Group(groupName) — sends to all clients in a named groupEvery client that connects to a SignalR Hub is assigned a unique, server-generated ConnectionId string. It identifies a single connection for the lifetime of that connection. If a client disconnects and reconnects, it receives a new ConnectionId.
ConnectionId is accessible inside Hub methods via Context.ConnectionId. It is used for targeted messaging, but should not be used as a stable user identifier — map ConnectionId to authenticated user identities when you need to send messages to a specific user across multiple connections.
Groups are named collections of connections. Any Hub method can add or remove a connection from a group using Groups.AddToGroupAsync and Groups.RemoveFromGroupAsync. You can then broadcast to all group members with Clients.Group(groupName).
Key limitations interviewers probe:
By default, SignalR uses in-memory state — each server only knows about its own connections. When you run multiple instances behind a load balancer, a client connected to Server A cannot receive a message sent on Server B.
The solution is a backplane: a shared message broker that all servers subscribe to. When one server sends a message, it publishes it to the backplane; all other servers receive and deliver it to their local clients.
Common backplanes:
Microsoft.AspNetCore.SignalR.StackExchangeRedisA senior candidate should also mention sticky sessions (affinity routing) as an alternative for simpler setups, and explain why it is not sufficient for true fault-tolerant scale-out.
Client-side reconnection behavior depends on the client library and configuration:
.withAutomaticReconnect() during connection builder configuration. By default it retries at 0, 2, 10, and 30 seconds. You can provide a custom retry policy.ConnectionId. Any group memberships, in-flight messages, and caller-specific state from the previous connection are lost unless the application rebuilds them.SendAsync — fire-and-forget. Sends the invocation to the server and does not wait for a return value. Returns Task (completes when the message is sent, not when the server handles it).InvokeAsync<T> — sends the invocation and awaits a return value from the server-side Hub method. The Hub method must return a typed value, and the client call must match that type.For read-heavy or result-driven operations, InvokeAsync is appropriate. For broadcast or notification-style calls where you do not need a confirmation, SendAsync is preferred for lower overhead.
SignalR provides Clients.User(userId) for sending to all connections associated with an authenticated user. This works through the IUserIdProvider interface, which by default resolves the user ID from ClaimTypes.NameIdentifier.
You can customize user ID resolution by implementing IUserIdProvider and registering it in DI. For example, you might resolve by email, tenant-scoped ID, or a custom claim.
Important detail: a single user can have multiple active connections (same user, different browser tabs). Clients.User(userId) sends to all of them simultaneously.
Inject IHubContext<THub> into the controller or service. This gives you access to Clients and Groups without being inside a Hub invocation. It is the correct pattern for proactive server-initiated pushes, such as a background job completing and notifying clients, or a webhook arriving and broadcasting an update.
IHubContext<THub> does not give you Context (which is per-connection). It is purely for outbound message delivery.
Hub methods and Hub connections can be protected at multiple levels:
[Authorize] to the Hub class itself. Unauthenticated clients are rejected during the negotiation/connection phase.[Authorize] or [Authorize(Roles = "...")] to individual Hub methods for fine-grained control.IAuthorizationService into the Hub and call AuthorizeAsync inside the Hub method with a resource-based policy.For JWT-based APIs, the access token must be passed differently because browsers cannot set authorization headers for WebSocket connections. The JavaScript SignalR client sends the token as a query string parameter (access_token). On the server, you configure OnMessageReceived in the JWT options to read the token from the query string — a detail interviewers specifically check.
Key areas a senior candidate should cover:
[EnableConcurrentExecution] (available in recent versions) if you need parallel execution per connection, but handle races yourself.IAsyncEnumerable<T> or ChannelReader<T>) for data that is large or emitted incrementally — financial ticks, log streams, progress updates.HubCallerContext and consider client-side acknowledgement patterns for high-throughput scenarios.SignalR supports two streaming patterns:
Server-to-client streaming: The Hub method returns IAsyncEnumerable<T> or ChannelReader<T>. The client subscribes and receives items as they are produced, rather than waiting for a complete response. Ideal for live data feeds, progress reporting, or paginated large datasets.
Client-to-server streaming: The client sends a stream of items to the Hub method (using IAsyncEnumerable<T> as the Hub method parameter). The Hub processes items as they arrive. Useful for chunked file uploads, live telemetry ingestion, or typed event streams.
The key advantage over single-value responses is backpressure alignment — neither side has to buffer the entire payload. Senior candidates should know that ChannelReader<T> gives manual control over the producer side, useful when the data source is not natively async-enumerable.
| ASP.NET Core SignalR (Self-Hosted) | Azure SignalR Service | |
|---|---|---|
| Connection handling | Managed by your servers | Offloaded to Azure |
| Scale-out | Requires Redis/backplane | Built-in, serverless-compatible |
| Connection limit | Bounded by server resources | Up to millions of concurrent connections |
| Operational overhead | High (infra, backplane, Redis) | Low (fully managed) |
| Cost model | Infrastructure cost | Per-connection/message pricing |
| Negotiation URL | Your server | Azure endpoint with token redirect |
For small-scale or on-premises applications, self-hosted is simpler. For cloud applications expecting thousands of concurrent users, Azure SignalR Service eliminates the backplane problem and the connection-per-server limit entirely.
Testing SignalR Hubs requires a different approach from standard controller tests:
IHubCallerClients, IGroupManager, and HubCallerContext using Moq or NSubstitute. Call the Hub method and assert the expected SendAsync calls were made on the mock.WebApplicationFactory to spin up the full ASP.NET Core host, then connect using the SignalR .NET client in tests. This validates the full pipeline including middleware, authentication, and routing.IHubContext<T>: Inject it as you would in production, mock it in unit tests for services that use it.A common interview question is to describe how you would assert that a Hub method broadcast to the correct group with the right payload — the answer involves capturing the SendAsync call on the mocked IGroupManager.Clients.Group(...) proxy.
Sticky sessions (or affinity routing) ensure that all requests from a specific client are routed to the same backend server. For SignalR, this matters because:
Sticky sessions solve the negotiation/WebSocket mismatch problem, but they do not solve the broadcast problem — messages sent on Server A still do not reach clients on Server B. For production multi-server deployments, a backplane is still required for full message fan-out. Sticky sessions can supplement a backplane setup (to reduce backplane load) but are not a replacement.
| Concept | What Interviewers Want to Hear |
|---|---|
| Hub lifecycle | Transient per invocation; don't store state in fields |
| ConnectionId | Resets on reconnect; map to user identity for persistence |
| Groups | Not persistent; must re-add after reconnect; need backplane to span servers |
| Scale-out | Redis backplane or Azure SignalR Service |
| Auth for WebSockets | Token via query string; read in OnMessageReceived |
| Streaming | IAsyncEnumerable<T> / ChannelReader<T> for incremental data |
| IHubContext | For outbound push from outside Hub; inject it anywhere |
| Testing | Mock IHubCallerClients; integration test with the .NET client |
If you are preparing for architecture-level interviews that also cover gRPC as an alternative transport, the ASP.NET Core gRPC Interview Questions article covers the questions interviewers use to probe gRPC knowledge for senior candidates.
☕ Prefer a one-time tip? Buy us a coffee — every bit helps keep the content coming!
Senior-level interviews expect you to go well beyond basic Hub setup. You should be able to explain transport negotiation, justify when to use SignalR versus alternatives like gRPC or SSE directly, describe scale-out strategies with Redis or Azure SignalR Service, and discuss production concerns such as authentication, reconnection handling, group lifecycle management, and performance at scale.
Yes. SignalR remains the standard for browser-facing real-time scenarios because it handles transport negotiation automatically, works across diverse client environments (browsers, mobile, desktop), and integrates directly with ASP.NET Core authentication and authorization. gRPC is preferred for service-to-service communication. SignalR and gRPC are complementary, not competing choices.
Browsers do not support custom headers for WebSocket connections. The standard approach for JWT authentication with SignalR is to pass the access token as a query string parameter (?access_token=...), which the JavaScript SignalR client does automatically when you configure the accessTokenFactory. On the server, you configure the JWT bearer handler's OnMessageReceived event to read the token from the query string. This is a detail interviewers specifically probe in senior interviews.
Inject IHubContext<THub> into the background service using the IServiceScopeFactory pattern (since Hubs are scoped and background services are singletons). Call Clients.All.SendAsync(...) or target groups and users as needed. Never instantiate a Hub directly or call Hub methods from outside the SignalR pipeline.
Group memberships are not persistent. When a client disconnects — whether normally or due to network failure — it is automatically removed from all groups it had joined. Your application is responsible for re-adding the user to the appropriate groups when they reconnect. This is typically done by overriding OnConnectedAsync in the Hub and restoring group membership from your application's state (e.g., a cache or database record of which groups the user belongs to).
The practical limit depends on hardware and connection type, but a single server can typically support 5,000–20,000 concurrent WebSocket connections before memory and file descriptor limits become the constraint. For higher concurrency, Azure SignalR Service removes this ceiling by offloading connection management entirely. For on-premises deployments, a Redis backplane with multiple server instances distributes the load.
Use streaming when: the total data volume is too large to buffer in a single response, data is generated incrementally over time (progress updates, financial ticks, sensor readings), or you want to begin delivering results to the client before the full dataset is available. For standard request/response where the server computes a result and returns it immediately, a regular Hub method or a REST endpoint is simpler and equally appropriate.