Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR 2.2 clients not receiving any messages

I have a self-hosted SignalR application running in the context of a console app. I'm connecting to the hubs within it through the use of a wrapper class to prevent me from having to reference the SignalR.Core assemblies from my ASP.NET project. So it's another C# class from within my application that's responsible for broadcasting messages to connected clients.

I'm able to call the PlanHub methods (Register and Unregister) directly from Javascript, those breakpoints get hit. However, when I call client methods from a class outside of the Hub (even if I use Clients.All to eliminate problems with the Group registration), the clients never get the message. What am I doing wrong?

When running this code, I can verify that the Clients.All.updateStatus(planId, message); code is being hit successfully, but nothing is logged to the console on the client.

Here's the relevant code:

PlanHub.cs

public class PlanHub : Hub
{
    private const string GroupPrefix = "PlanGroup_";

    public void Register(int companyId)
    {
        Groups.Add(Context.ConnectionId, $"{GroupPrefix}{companyId}");
    }

    public void Unregister(int companyId)
    {
        Groups.Remove(Context.ConnectionId, $"{GroupPrefix}{companyId}");
    }
}

PlanPublisher.cs

public class PlanPublisher
{
    private readonly static Lazy<PlanPublisher> _instance = new Lazy<PlanPublisher>(() => 
        new PlanPublisher(GlobalHost.ConnectionManager.GetHubContext<PlanHub>().Clients));
    private IHubConnectionContext<dynamic> Clients { get; set; }

    private PlanPublisher(IHubConnectionContext<dynamic> clients)
    {
        Clients = clients;
    }

    public static PlanPublisher Instance => _instance.Value;

    public void UpdateStatus(int planId, string message)
    {
        //This code gets hit and no exceptions are thrown, but the clients
        //never receive the message. Using Clients.All instead of my 
        //Groups for testing -- still doesn't work
        Clients.All.updateStatus(planId, message);
    }
}

Calling code (from within another C# class)

PlanPublisher.Instance.UpdateStatus(plan.Id, $"Publishing started for {plan.Name}...");

Javascript

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script> 
<script src="~/scripts/jquery.signalR-2.2.0.min.js"></script>
<script src="http://localhost:8080/signalr/hubs"></script>
<script>
    $(document).ready(function() {
        $.connection.hub.url = "http://localhost:8080/signalr";

        var planMessagePublisher = $.connection.planHub;

        planMessagePublisher.client.updateStatus = function (planId, message) {
            console.log('Status: ' + planId + ' - ' + message);
        };

        $.connection.hub.start().done(function() {
            //This works! My PlanHub.Register method gets called successfully
            planMessagePublisher.server.register(@Model.CompanyId);

            // New connection ID is successfully sent to console
            console.log('Now connected, connection ID=' + $.connection.hub.id);
        });
    });
</script>

JS Console Debugger Output

jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Auto detected cross domain url.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Client subscribed to hub 'planhub'.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Negotiating with 'http://localhost:8080/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22planhub%22%7D%5D'.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: webSockets transport starting.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Connecting to websocket endpoint 'ws://localhost:8080/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=AQAAANCMnd8BFdERjHoAwE%2FCl%2BsBAAAA5D8YUVyzBEG4tTlTaGn0MgAAAAACAAAAAAADZgAAwAAAABAAAABDjF1MaCTzZI0XTM8gC29xAAAAAASAAACgAAAAEAAAAKrk0jv%2FKF4YFzDvNwmSR8IoAAAAacm1d1r7dJpjOtVtCFIFRpugkubyZm1e5Z8OtOFtnhZyEBO1SO4lqhQAAABiG7hBydTiypPh8k2ZYz20ropNxw%3D%3D&connectionData=%5B%7B%22name%22%3A%22planhub%22%7D%5D&tid=6'.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Websocket opened.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: webSockets transport connected. Initiating start request.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: The start request succeeded. Transitioning to the connected state.
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Now monitoring keep alive with a warning timeout of 13333.333333333332, keep alive timeout of 20000 and disconnecting timeout of 30000
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Invoking planhub.Register
jquery.signalR-2.2.0.min.js?v=8588299:8 [06:23:19 GMT-0700 (Pacific Daylight Time)] SignalR: Invoked planhub.Register

It registers successfully, but never receives any data. The Clients.All.updateStatus(planId, message); breakpoint was hit multiple times but the console never received any additional logging data.

EDIT: It was suggested that I look into whether or not a custom dependency resolver is in play. The code posted here lives in its own project with very little else, other than what you see here. The code that calls PlanPublisher.UpdateStatus() DOES have a custom dependency resolver, but that shouldn't matter since it's isolated in its own assembly. PlanPublisher.cs and PlanHub.cs are contained in a very simple project that just has references to SignalR.Core and SignalR.SelfHost.

like image 338
Scott Avatar asked Apr 30 '16 13:04

Scott


1 Answers

I tried to simplify your example (using SignalR 2.2.0)

Hub class:

public class PlanHub : Hub
{
    private const string GroupPrefix = "PlanGroup_";

    // hubcontext
    private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext <PlanHub> ();

    public void Register(int companyId)
    {
        Groups.Add(Context.ConnectionId, $"{GroupPrefix}{companyId}");
    }

    public void Unregister(int companyId)
    {
        Groups.Remove(Context.ConnectionId, $"{GroupPrefix}{companyId}");
    }

    // static method using hub context
    public static void Static_UpdateStatus(int planId, string message)
    {
        hubContext.Clients.All.updateStatus(planId, message);
    }
}

Since I don't really have a backend and I don't know how you are going to do that, I just set up a timer to call the method from C# every 10 seconds.

Calling and dummy timer:

    public void startTimer()
    {
        timer = new System.Timers.Timer();
        timer.Elapsed += new System.Timers.ElapsedEventHandler(ExecuteTimerJob);
        timer.Interval = 10000; // 10 sec
        timer.Start();
    }

    public static void ExecuteTimerJob(object source, System.Timers.ElapsedEventArgs e)
    {
        // this is the call from C#
        PlanHub.Static_UpdateStatus(123, "some message");
    }

JS:

$(function () {
    var planHub = $.connection.planHub;
    $.connection.hub.start().done(function () {
         console.debug('Connected to PlanHub...');
    })
    planHub.client.updateStatus = function (planId, message) {
        console.log("planId: " + planId);
        console.log("message: " + message);
    } 
});

Result in browser console:

enter image description here

like image 144
DDan Avatar answered Sep 17 '22 15:09

DDan