SignalR C# Client Hubconnection.On not fired
Asked Answered
A

2

6

I have a ASPNet.Core WebApi, with signalR. I have angular app, that consumes the webAPI, and I want to replace it with a Blazor Webassembly app. I have a problem with signalR in the Blazor app.

I create a hubconnection, set it up, and when the server sends data, the Hubconnection.On method is not invoked. Here's my code:

protected override async Task OnInitializedAsync()
{
    _hubConnection = new HubConnectionBuilder()
        .WithUrl("https://localhost:45299/hubs/accounthub", cfg =>
        {
            cfg.SkipNegotiation = true;
            cfg.AccessTokenProvider = () => Task.FromResult(token);
            cfg.Transports = HttpTransportType.WebSockets;
        })
        .Build();

    _hubConnection.On<IEnumerable<AccountResponse>>("accountschanged", (accounts) =>
    {
        foreach(var account in accounts)
        {
            Console.WriteLine(account.Name);
        }
    });
    await _hubConnection.StartAsync();
}

In the network tab, I see that the connection is ok, I receive new data, but the method in hubconnection.On doesn't get fired. I double checked the method name, and it is the same. In the angular app it works fine and as data gets send from the server, I don't there's any problem with the server code.

I use Fluxor for state management, and I fire an action in the 'On' method, I just replaced is with a single Console.WriteLine for simplicity.

Edit: Added server code, and the message received Here's the server code, 'AccountsChanged' is called when an account is changed:

public class AccountHub : Hub, IAccountHub
{
    private readonly IHubContext<AccountHub> _accHub;
    private readonly IAggregateMapper _mapper;

    public AccountHub(IHubContext<AccountHub> accHub, IAggregateMapper mapper)
    {
        _accHub = accHub;
        _mapper = mapper;
    }

    public async Task AccountsChanged(Guid userId, IEnumerable<Account> accounts)
    {
        var mapped = _mapper.MapAll<Account, AccountResponse>(accounts);
        await _accHub.Clients.User(userId.ToString()).SendAsync("accountschanged", mapped);
    }
}

And here's the message I receive (I make a request from Postman), copied from the network tab (I removed additional properties of accounts to keep it simple):

{
    "type":1,
    "target":"accountschanged",
    "arguments":[
        [
            {
                "id":1,
                "name":"bank account 1"
            },
            {
                "id":2,
                "name":"wallet 1"
            }
        ]
    ]
}
Antrorse answered 13/7, 2020 at 8:39 Comment(7)
You're passing in a string with the value 'url' in the call to WithUrlSearle
I'm passing the right url, just replaced it. I wouldn't get any messages if the url was wrong. I'll edit it the post not to confuse anyone.Antrorse
Can you include the code to whatever that's posting the message on the hub methodSearle
I added the server code, and the message I receive from the hub.Antrorse
Do you see any errors in the debug output window in Visual Studio when running your Blazor app ?Searle
Also try adding async in your on handler: _hubConnection.On<IEnumerable<AccountResponse>>("accountschanged", async (accounts) =>Searle
There's no error in output, or browser console. I tried adding asnyc, and await Task.CompletedTask at the end of the function, but nothing has changed.Antrorse
A
9

I finally found the problem. It was about serializing the received json message. I had to add .AddJsonProtocol(), and set it up, here is the final code:

_hubConnection = new HubConnectionBuilder()
    .WithUrl("http://localhost:59225/hubs/accounthub", cfg =>
    {
        cfg.SkipNegotiation = true;
        cfg.Transports = HttpTransportType.WebSockets;
        cfg.AccessTokenProvider = () => Task.FromResult(token);
    })
    .AddJsonProtocol(cfg =>
    {
        var jsonOptions = new System.Text.Json.JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
        };
        jsonOptions.Converters.Add(new JsonStringEnumConverter());

        cfg.PayloadSerializerOptions = jsonOptions;
    })
    .Build();

I find it strange that I didn't get any error message btw.

Antrorse answered 14/7, 2020 at 9:46 Comment(2)
Also you need to add using Microsoft.Extensions.DependencyInjection: learn.microsoft.com/en-us/aspnet/core/signalr/…Maurinemaurise
I have the same error, but this answer doesn't work :(Roundlet
G
1

For those still finding this issue, I was using Blazor server & I had a very similar problem, however for me, the issue was because I did not have empty constructors on the objects I was sending back. Don't make the same silly mistake I made!

I had something similar to the below, however my RoomDTO object did not have a empty constructor.

hub.cs

List<RoomDTO> rooms = await _chatService.GetAllRoomsAsync();
await Clients.Caller.SendAsync("PushRoomsList", rooms);

component.cs

hubConnection?.On<List<RoomDTO>>("PushRoomsList", HandleRoomsList);
Giaour answered 20/10, 2023 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.