Search code examples
c#signalr.net-6.0

SignalR .NET 6 Client Not adding handler


So, I am trying to do a SIMPLE task with SignalR right now. Basically, I have a console app that will have .NET SignalR client, and a .NET 6 Web API with SignalR server.

I am just trying to do a simple flow:

  1. Client sends request to SignalR Hub
  2. Hub processes request, and returns data back to .NET client

I have no user interaction at all, that's why I'm not using JS, as this will not be in the browser.

Here is my current setup for the SignalR Server

OnPremAgentClientHub in Web API:

using Microsoft.AspNetCore.SignalR;

namespace HttpLongPollingServer.Hubs
{
    public sealed class OnPremClientHub : Hub
    {
        public async Task GetOnPremAgentStatus(string clientIp)
        {
            bool isReachable = OnPremAgentData.IsAgentPingable(clientIp)
            await Clients.Caller.SendAsync("OnPremAgentStatusReceived", isReachable);
        }
    }
} 

The relevant code from Program.cs in Web API for SignalR setup:

app.MapHub<OnPremClientHub>("/clienthub", options => 
    {
        options.Transports = HttpTransportType.LongPolling;
    });

Yes, I want to force HTTP Long polling.

Here is my setup in the console app for SignalR client

Program.cs

var hubConnection = new HubConnectionBuilder()
    .WithUrl("https://localhost:7184/clienthub")
    .WithAutomaticReconnect()
    .ConfigureLogging(logging =>
        {
            logging.AddConsole();
            // This will set ALL logging to Debug level
            logging.SetMinimumLevel(LogLevel.Debug);
        })
    .Build();

await hubConnection.StartAsync();



await LongPollingTest.TestHttpSignalRLongPolling(hubConnection);

The TestHttpSignalRLongPolling that calls the SignalR Hub methods:

public static async Task TestHttpSignalRLongPolling(HubConnection hubConnection) 
        {
            await hubConnection.InvokeAsync("GetOnPremAgentStatus", arg1: "192.168.19.128");

            hubConnection.On("OnPremAgentStatusReceived", (bool isReachable) => {
                if (isReachable)
                    Console.WriteLine("Agent is reachable");
                else
                    Console.WriteLine("Agent is not reachable");
            });
        }

Now, I can get the client to invoke the GetOnPremAgentStatus. However, when the client goes to do the hubConnection.On()... I get the following Warning and Error

Microsoft.AspNetCore.SignalR.Client.HubConnection[14] Failed to find handler for 'OnPremAgentStatusReceived' method. fail: Microsoft.AspNetCore.SignalR.Client.HubConnection[57] Failed to bind arguments received in invocation '(null)' of 'OnPremAgentStatusReceived'. System.IO.InvalidDataException: Invocation provides 1 argument(s) but target expects 0. at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.BindTypes(Utf8JsonReader& reader, IReadOnlyList`1 paramTypes)

I'm banging my head against a wall. I feel it's something simple I'm missing, I just don't know what it is.

Any tips or help is appreciated!


Solution

  • Alright, so the answer was staring me straight in the face in the Microsoft docs. The problem was that I was trying to call a callback on an unregistred handler that is located in my Server Hub in my client code. The fix was easy. I simply moved my connection.On to Program.cs after making my Hub Connection, but before starting the connection.

    Updated Program.cs looks like this:

    using Microsoft.AspNetCore.SignalR.Client;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using HttpLongPollingClientConsole;
    
    ServiceProvider service = new ServiceCollection()
        .AddLogging((loggingBuilder) => loggingBuilder
        .SetMinimumLevel(LogLevel.Debug)
        .AddConsole()
        .AddDebug())
        .BuildServiceProvider();
    
    var hubConnection = new HubConnectionBuilder()
        .WithUrl("https://localhost:7184/clienthub", options => 
        {
            options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling;
        })
        .WithAutomaticReconnect()
        .ConfigureLogging(logging =>
            {
                logging.AddConsole();
                // This will set ALL logging to Debug level
                logging.SetMinimumLevel(LogLevel.Debug);
            })
        .Build();
    
    // Register the handler here!! 
    hubConnection.On<bool>("OnPremAgentStatusReceived", (isReachable) => {
        if (isReachable)
            Console.WriteLine("Agent is reachable");
        else
            Console.WriteLine("Agent is not reachable");
    });
    
    hubConnection.StartAsync().Wait();
    
    await LongPollingTest.TestHttpSignalRLongPolling(hubConnection);
    
    Console.ReadKey();
    

    This is explained in the Microsoft Docs very well.

    Now, from my Debug output of the SignalR client I can see the Handler being registered properly.

    dbug: Microsoft.AspNetCore.SignalR.Client.HubConnection[40] Registering handler for client method 'OnPremAgentStatusReceived'.