Search code examples
signalrasp.net-core-signalrsignalr-client

SignalR core console client not receiving notifications


I have looked around at some of the Similar questions and didn't figure this problem out. I have a simple Hub in my .NET core Web API project. Here is the Hub:

 public class NotificationHub : Hub<INotificationClient>
{
  public async Task SendMessage(string user, string msg)
    {
        await Clients.All.ReceiveMessage(user, msg);
    }
    public Task SendMessageToCaller(string msg)
    {
        return Clients.Caller.ReceiveMessage(msg);
    }

    public Task SendMessageToPartner(string user, string msg)
    {
        return Clients.Client(user).ReceiveMessageToPartner(msg);
    }
}

Here is the Interface:

 public interface INotificationClient
{
    Task ReceiveMessage(string user, string msg);
    Task ReceiveMessage(string msg);
    Task ReceiveMessageToPartner( string msg);

}

Here is the code from the controller:

[Route("[controller]")]
[ApiController]
public class NotificationsController : ControllerBase
{
    private IHubContext<NotificationHub> _hub;

    public NotificationsController(IHubContext<NotificationHub> hub)
    {
        _hub = hub;

    }
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var msg = new NotificationData { ClientId = "12345", Notification = "Somone just connected" };
        await _hub.Clients.All.SendAsync("Notification", msg);
        return Ok(new { Message = "Request complete" });
    }
}

Lastly here is the console client code:

 Console.WriteLine("Press a key to start listening");
        Console.ReadKey();

        Console.WriteLine("Client Listening!");
        var connection = new HubConnectionBuilder()
           .WithUrl("http://localhost:61514/notifications")

           .Build();


        connection.On<NotificationData>("Notification", (notificationData) =>
            Console.WriteLine($"Somebody connected: {notificationData.ClientId}"));

        connection.StartAsync().GetAwaiter().GetResult();

        Console.WriteLine("Listening. Press a key to quit");
        Console.ReadKey();

Here is the startup of the web app with the mappings:

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR();
        services.AddControllers();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapHub<NotificationHub>("/Notifications");
        });
    }

I keep getting this error: System.IO.IOException: 'The server disconnected before the handshake could be started.' I must be missing something along the way here.

Update:
Turned on the logs and got this error:

dbug: Microsoft.AspNetCore.Http.Connections.Client.HttpConnection[8] Establishing connection with server at 'http://localhost:61514/notifications'. dbug: Microsoft.AspNetCore.Http.Connections.Client.HttpConnection[9] Established connection 'BdROAEEQnGUeDYAW5EspRA' with the server. dbug: Microsoft.AspNetCore.Http.Connections.Client.HttpConnection[7] Starting transport 'ServerSentEvents' with Url: http://localhost:61514/notifications. info: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[1] Starting transport. Transfer mode: Text. dbug: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[3] Starting receive loop. dbug: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[9] Received 30 bytes. Parsing SSE frame. dbug: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[4] Receive loop stopped. dbug: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[100] Starting the send loop. dbug: Microsoft.AspNetCore.Http.Connections.Client.HttpConnection[18] Transport 'ServerSentEvents' started. dbug: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[102] Send loop canceled. dbug: Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport[101] Send loop stopped. Unhandled exception. info: Microsoft.AspNetCore.Http.Connections.Client.HttpConnection[3] HttpConnection Started. info: Microsoft.AspNetCore.SignalR.Client.HubConnection[24] Using HubProtocol 'json v1'. System.IO.IOException: The server disconnected before the handshake could be started. at Microsoft.AspNetCore.SignalR.Client.HubConnection.HandshakeAsync(ConnectionState startingConnectionState, CancellationToken cancellationToken) at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncCore(CancellationToken cancellationToken) at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncCore(CancellationToken cancellationToken) at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncInner(CancellationToken cancellationToken) at System.Threading.Tasks.ForceAsyncAwaiter.GetResult() at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsync(CancellationToken cancellationToken) at NotificationClient.Program.Main(String[] args)


Solution

  • So after chonking on this all day, I found out what the problem was, so I thought I'd post the solution here just in case someone else is having this problem.

    The Hub Endpoint was pointing to the controller. So when the client was linking it was hitting the controller twice causing a the server to close the connection. So I changed this line:

    app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<NotificationHub>("/Notify");
            });
    

    from "/Notifications" which was hitting the controller, to "Notify" as in the code above, re-pointed the client from Notifications to Notify

     var connection = new HubConnectionBuilder()
               .WithUrl("http://localhost:61514/Notify")
              .ConfigureLogging(logging =>
              {
                  logging.AddConsole();
                  logging.SetMinimumLevel(LogLevel.Debug);
              })
               .Build();
    

    and messages started to flow in.