Search code examples
c#blazorsignalr

SignalR hub method is not getting called in Blazor


I'm using .Net 8.0 in Blazor.

I have a server project and a client project.

The server receives a notification via a controller method and this should invoke a method on the signalR hub to 'push' a notification to all clients. The issue is that the Hub Method never gets called.

On the server I have the following code:

In the program.cs file:

builder.Services.AddSignalR();
.....
app.MapHub<NotificationHub>("/notificationhub");

I have created my Hub:

public class NotificationHub : Hub 
{

    [HubMethodName("SendBookingStatusUpdate")]
    public async Task SendBookingStatusUpdate()
    {
       await Clients.All.SendAsync("ReceiveBookingStatusUpdate");
    }
}

I then have a controller that will call the hub method:

public class NotificationController : ControllerBase
{
    private readonly IHubContext<NotificationHub> _notificationHub;

    public NotificationController(IHubContext<NotificationHub> notificationHub)
    {
        _notificationHub = notificationHub;
    }
    [HttpPost("statuschange")]
    public async Task StatusChange()
    {
        try
        {
             await _notificationHub.Clients.All.SendAsync("SendBookingStatusUpdate");
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

In my client on one of my code behind pages I have:

private HubConnection? hubConnection;
   

protected override async Task OnInitializedAsync()
{
    await ScreenTasks();

    hubConnection = new HubConnectionBuilder()
   .WithUrl(Navigation.ToAbsoluteUri("/notificationhub"))
   .WithAutomaticReconnect()
   .Build();
    
    hubConnection.Closed += async (err) => { await Task.Delay(4000); await hubConnection.StartAsync(); };

    hubConnection.On("ReceiveBookingStatusUpdate", async () =>
    {
        await ScreenTasks();
        StateHasChanged();
           
    });

    await hubConnection.StartAsync();
}

public async ValueTask DisposeAsync()
{
    if (hubConnection is not null)
    {
        await hubConnection.DisposeAsync();
    }
}

When I step the code, at the end of my clients onInitializedAsync method when I look at the hubconnection I can see the connection id.

If I make a call to my StatusChange method in my Notification Controller, when I look at the _notificationHub connectionId, this is also the same as the Id from my client so all seems ok at this point. My code hits' my method in my try block and just passes through. It does not go into the notificationHub SendBookingStatusUpdate method and the code does not hit my catch block. What do I need to do to ensure my hub method get's called.


Solution

  • Install this package from Nuget: Microsoft.AspNetCore.SignalR.Client

    Then modify your controller as below:

        public class NotificationController : ControllerBase
        {
            [HttpPost("statuschange")]
            public async Task StatusChange()
            {
                try
                {
                    //Replace with your application url that hosts the hub
                    var connection = new HubConnectionBuilder().WithUrl("https://localhost:7234/notificationhub").Build();
                    //Connect to SignalR hub as client
                    await connection.StartAsync();
                    //Check if connection established
                    if (connection.State == HubConnectionState.Connected)
                    {
                        //Invoke SignalR method
                        await connection.InvokeAsync("SendBookingStatusUpdate");
                    }
                }
                catch (Exception ex)
                {
                    throw;
                }
            }
        }
    

    In this way you are connecting to the hub as client then sending the message, while the code you have provided is just to interact with hub from outside hub itself which is not recommended for many reasons