Skip to content

ASP.NET SignalR Connection Error Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about ASP.NET SignalR Connection Error Fix. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The SignalR client connects but Invoke or SendAsync never reaches the server:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .build();

connection.invoke("SendMessage", "Hello").catch(err => console.error(err));

The client connects successfully (the connection.on handlers work) but the hub method is never invoked on the server. The issue is often a mismatch between the method name casing, hub route configuration, or required authorization.

Step-by-Step Fix

1. Match method name casing exactly

WRONGJavaScript sends camelCase but C# expects PascalCase:

connection.invoke("sendMessage", "Hello"); // lowercase 's'

RIGHT — use the exact .NET method name:

connection.invoke("SendMessage", "Hello"); // PascalCase

Or configure camelCase in the hub:

builder.Services.AddSignalR()
    .AddHubOptions<ChatHub>(options =>
    {
        options.UseCamelCaseSerialization = true;
    });

2. Verify hub route registration

WRONG — missing endpoint mapping:

var app = builder.Build();
app.MapControllers();
// Missing: app.MapHub<ChatHub>("/chatHub");

RIGHT — register the hub endpoint:

var app = builder.Build();
app.MapControllers();
app.MapHub<ChatHub>("/chatHub");

The JavaScript URL must exactly match the route:

.withUrl("/chatHub") // matches the MapHub route

3. Handle CORS for cross-origin clients

WRONG — default CORS policy blocks SignalR requests:

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.AllowAnyOrigin(); // Not allowed with AllowCredentials
    });
});

RIGHT — use specific origins with AllowCredentials:

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins("https://myapp.com")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials();
    });
});

SignalR requires AllowCredentials because it uses the negotiate endpoint to upgrade the connection.

4. Check authorization on hub methods

WRONG — hub method requires auth but client is not authenticated:

[Authorize]
public class ChatHub : Hub
{
    public async Task SendMessage(string message)
    {
        // Only authenticated users can call this
    }
}

RIGHT — allow anonymous or pass the token:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub", {
        accessTokenFactory: () => getAuthToken()
    })
    .build();

Or make the method public if auth is not needed:

[AllowAnonymous]
public async Task SendMessage(string message)

5. Force WebSocket transport

WRONG — letting SignalR negotiate, which may fall back to long polling:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .build();

RIGHT — specify WebSocket transport explicitly:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .withUrl("/chatHub", signalR.HttpTransportType.WebSockets)
    .build();

Expected output: WebSocket connection established, WebSocket closed with code 1000.

Prevention

  • Use consistent PascalCase method naming between client and server.
  • Always register MapHub in your app pipeline.
  • Configure CORS with specific origins and AllowCredentials for cross-origin clients.
  • Check browser DevTools Network tab for negotiate endpoint responses.
  • Use withAutomaticReconnect on the client for resilience.

Common Mistakes with signalr error

  1. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  2. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  3. Using head and tail instead of pattern matching, causing runtime errors on empty lists

These mistakes appear frequently in real-world ASPNET code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does SignalR fall back to long polling instead of WebSocket?

The server or a proxy (like Azure App Service, Cloudflare, or nginx) might not support WebSocket. Check if WebSocket is enabled on the server and if intermediaries support the WebSocket upgrade.

How do I debug SignalR connection issues?

Set the log level to Debug on both client and server. On the client: .configureLogging(signalR.LogLevel.Debug). On the server: set Logging:SignalR:Default to Debug in appsettings.json.

Can SignalR work without WebSocket?

Yes. SignalR automatically falls back to Server-Sent Events, then Long Polling if WebSocket is unavailable. This ensures compatibility with older browsers and restrictive networks.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro