I have developed a unique self-hosted SignalR application that is operating within the framework of a console application. To access the hubs within this application, I have implemented a wrapper class to avoid referencing the SignalR.Core assemblies directly in my ASP.NET project. This way, another C# class within my application is responsible for transmitting messages to connected clients.
Although I am able to interact with the PlanHub
methods (Register
and Unregister
) directly from Javascript and reach breakpoints successfully, I encounter an issue when attempting to call client methods from a different class outside of the Hub. Even when using Clients.All
to rule out concerns with Group registration, the message does not reach the intended clients. What could be causing this problem?
Upon examining the code, it appears that the line
is executed without errors, but no data is displayed on the client's console log.Clients.All.updateStatus(planId, message);
Here are the key sections of the 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)
{
//Despite no exceptions being thrown, the message is not received by clients.
//Even testing with Clients.All instead of Groups did not resolve the issue.
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() {
//The PlanHub.Register method executes successfully at this point.
planMessagePublisher.server.register(@Model.CompanyId);
// Also successfully logs the new connection ID to the 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'.
...
Despite correct registration, the expected data does not propagate to the clients. The line
Clients.All.updateStatus(planId, message);
gets triggered multiple times, yet the additional logging data never reaches the console as anticipated.
UPDATE: Inquiring about a potential custom dependency resolver, the presented code resides isolated within its own project with minimal external components besides what has been showcased here. Although the section calling PlanPublisher.UpdateStatus()
does feature a custom dependency resolver, this should not affect operations since it is segregated within its distinct assembly. Both PlanPublisher.cs
and PlanHub.cs
exist within a simplistic project solely linked to SignalR.Core and SignalR.SelfHost.