Search code examples
c#blazorsignalrblazor-server-sidesignalr-hub

Configured hub URL not used for Blazor server + SignalR hub


In .NET 9 I've created a default Blazor Web app project and added a SignalR hub that is used for sending notifications between clients.

When one session increments the value for /counter, all sessions are notified of this and updates their displayed value. This all works.

What I don't understand is why in the browser developer tools, there's no connection to the configured Hub URL. There is only the standard Blazor server websocket to /_blazor.

The code-behind for Counter.razor is updated like this:

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;
    private HubConnection _hubConnection;
    
    public async ValueTask DisposeAsync()
    {
        await _hubConnection.DisposeAsync();
    }
    
    protected override async Task OnInitializedAsync()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri(CounterHub.HubUrl))
            .Build();
        
        _hubConnection.On<CounterNotification>(CounterHub.CounterUpdatedMethod, HandleCounterUpdated);
        await _hubConnection.StartAsync();
    }

    private void HandleCounterUpdated(CounterNotification notification)
    {
        currentCount = notification.Counter;
        InvokeAsync(StateHasChanged);
    }

    private async Task IncrementCount()
    {
        await CounterHubContext.Clients.All.SendAsync(CounterHub.CounterUpdatedMethod, new CounterNotification(currentCount + 1));
    }
}

CounterHub.cs is implemented like this:

public class CounterHub : Hub
{
    public const string HubUrl = "/counter-notifications";
    public const string CounterUpdatedMethod = "CounterUpdated";

    public override Task OnConnectedAsync()
    {
        Console.WriteLine("{0} connected", Context.ConnectionId);
        return base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception? e)
    {
        Console.WriteLine("{0} disconnected", Context.ConnectionId);
        await base.OnDisconnectedAsync(e);
    }
}

CounterNotification.cs looks like this:

public record CounterNotification(int Counter)
{
    public CounterNotification() : this(0) { }
}

It's all hooked up in Program.cs with the additions of these lines:

builder.Services.AddSignalR();

builder.Services.AddResponseCompression(opts =>
{
    opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
        ["application/octet-stream"]);
});

app.UseResponseCompression();

app.MapHub<CounterHub>(CounterHub.HubUrl);

With this, I would expect to see a websocket open up to /counter-notifications. But there's nothing. What's going on? Is the default Blazor websocket connection reused for the custom SignalR?

Firefox developer tools showing only one websocket connection


Solution

  • With this, I would expect to see a websocket open up to /counter-notifications. But there's nothing. What's going on?

    You won't see the connection just because the client is the blazor app instead of your browser,the browser didn't connect to /counter-notifications directly

    public class CounterHub : Hub
     {
         public const string HubUrl = "/counter-notifications";
         public const string CounterUpdatedMethod = "CounterUpdated";
    
         public override Task OnConnectedAsync()
         {
             Console.WriteLine("/counter-notifications-{0} connected", Context.ConnectionId);
             return base.OnConnectedAsync();
         }
    
         public override async Task OnDisconnectedAsync(Exception? e)
         {
             Console.WriteLine("{0} disconnected", Context.ConnectionId);
             await base.OnDisconnectedAsync(e);
         }
     }
    

    when you debug with kestrel,open the console you would see: enter image description here