SignalR OnConnected Not Hitting But Still Able to Invoke Client Side Functions From Server - signalr

I have the following TestHub that does nothing but invoke a client side sayHello() function.
public class TestHub:Hub
{
public void SayHello()
{
Context.Clients.All.sayHello();
}
public override Task OnConnected()
{
//do some custom stuff
return base.OnConnected();
}
}
On the client, I have the following:
var connection = $.hubConnection('http://localhost:12345/signalr');
var proxy = connection.createHubProxy('TestHub');
proxy.on('sayHello',function(){
console.log('sayHello fired');
})
connection.start().done(function(){
console.debug('Connected');
})
When I call SayHello() on my TestHub the client prints out the following perfectly fine
sayHelloFired
and when the proxy first loads, it prints the following to the console perfectly fine.
Connected
However, if I throw a breakpoint in the OnConnected() method on TestHub, then it does not hit.
All the posts discussing similar problems suggest that their is no handlers being subscribed on the client side, but that is not the case here. How could this be working and OnConnected() is never fired?

Your code didn't compile for me because of the
Context.Clients.All.sayHello();
Line. Context here tries to refer to Hub.Context which is an HubCallerContext class. I think you want to refer to Hub.Clients which is an IHubCallerConnectionContext.
I replaced that line to
Clients.All.sayHello();
And my breakpoint got invoked.
However I am surprised you made it run and got messages on console.
BTW You are right about that, when using javascript clients, if there is no subscription to any event in the hub, the OnConnected methond won't be invoked.
But that is not the case here.

Related

How to asynchronously await an Akka.Actor event?

I am using akka.NET. In most cases we use akka like this:
class ActorA : UntypedActor
{
public delegate void EventHandler(object arg1, object arg2, ...);
public static event EventHandler Event;
}
actorA.Event += some_function;
In this case we execute some_function(arg1, arg2) whenever Event.Invoke(arg1, arg2) is called. Now assume that we have an asynchrounous HTTP server, and I am trying to let the server asynchronously await actorA.Event to happen, after a client calls the server. I do not need to run some_function when Event happens, but I have to ensure that the runtime context is switched back into the functions of the HTTP server. That is:
// in the methods of the HTTP server...
public async void AwaitAnEvent()
{
await ReturnOnEvent(actorA.Event);
}
Is it possible to efficiently implement ReturnOnEvent which returns immediately when the next actorA.Event.Invoke(arg1, arg2) is called?
This case smells a bit.
inside the web controller just ask your actor and that will trigger it to generate response.
When asking it will await in the controller to get response.
var response = myActor.Ask<ResponseType>(new GiveMySomeFoodMsg());
-- in the actor
Sender.Tell(new ResponseType(some data here))

SignalR - How to call server function with parameter from client using hubproxy

I have my signalr running on a separate domain. We will have multiple applications using it to send and receive messages. I created the connection and hub proxy using the following code
connection = $.hubConnection("https://someurl.com", { useDefaultPath: false });
chatHub = connection.createHubProxy('chatHub');
I can get messages from the server sent to the client using the following code which works fine
chatHub.on('receiveEntityMessage', function (chatMessage) {
if (chatMessage) {
console.log(chatMessage.Message);
}
});
Now I dont know how to call server functions with parameters from the client. Can anybody please help me with this?
chatHub.invoke("MethodName", param1, param2, param3).done(function(result) {
console.log(result);
});
Since i'm not sure what is the language of your server side, i am going to provide a C# example.
C# Hub method example:
public class chatHub: Hub {
public void YourHubMehotd(int firstParam, string secondParam){
//The action of your method
}
}
JS client side:
You can call your hub method like this:
{The variable with the hub connection}.server.{the method you want to call}( {the parameters} )
Example:
chatHub.server.YourHubMehotd(1,"Example");
I recomend to create a js function to call the hub method.
function callMyHubMethod(firstParam, secondParam){
chatHub.server.YourHubMehotd(firstParam, secondParam);
}

SignalR - access clients from server-side business logic

I have a requirement to start a process on the server that may run for several minutes, so I was thinking of exposing the following hub method:-
public async Task Start()
{
await Task.Run(() => _myService.Start());
}
There would also be a Stop() method that allows a client to stop the running process, probably via a cancellation token. I've also omitted code that prevents it from being started if already running, error handling, etc.
Additionally, the long-running process will be collecting data which it needs to periodically broadcast back to the client(s), so I was wondering about using an event - something like this:-
public async Task Start()
{
_myService.AfterDataCollected += AfterDataCollectedHandler;
await Task.Run(() => _myService.Start());
_myService.AfterDataCollected -= AfterDataCollectedHandler;
}
private void AfterDataCollectedHandler(object sender, MyDataEventArgs e)
{
Clients.All.SendData(e.Data);
}
Is this an acceptable solution or is there a "better" way?
You don't need to use SignalR to start the work, you can use the applications already existing framework / design / API for this and only use SignalR for the pub sub part.
I did this for my current customers project, a user starts a work and all tabs belonging to that user is updated using signalr, I used a out sun library called SignalR.EventAggregatorProxy to abstract the domain from SignalR. Disclaimer : I'm the author of said library
http://andersmalmgren.com/2014/05/27/client-server-event-aggregation-with-signalr/
edit: Using the .NET client your code would look something like this
public class MyViewModel : IHandle<WorkProgress>
{
public MyViewModel(IEventAggregator eventAggregator)
{
eventAggregator.Subscribe(this);
}
public void Handle(WorkProgress message)
{
//Act on work progress
}
}

SignalR and Hub Persistance

I am trying out SignalR, and i don't quite understand how to call methods from my client in a way that it calls the same hub.
i have two methods in my hub:
private ctlDataManager myManager;
public void StartConnection()
{
myManager = new ctlDataManager("test");
myManager.UpdateItemEvent += myManager_UpdateItemEvent;
myManager.Connect();
}
public void StopConnection()
{
myManager.Disconnect();
}
And in my client i try to call them like this:
var notificationHub = $.connection.notificationHub;
$.connection.hub.start()
.done(function (state) {
$("#submit").click(function (e) {
e.preventDefault();
notificationHub.server.startConnection();
return false;
});
$("#stop").click(function (e) {
e.preventDefault();
notificationHub.server.stopConnection();
return false;
});
});
Now when i click on the start button it works fine it starts it and receives data too.
But when i click the stop button it throws an instance of an object error.
It appears that 'myManager' is null. It's almost as a new hub were open. Naturally i need it to be the same one as i need to close the connection.
How can i do that?
From my understanding, the server-side hub class is not persisted. Therefore, the myManager object is created with each method call from a client. My advice would be to declare myManager elsewhere in your application that you can assure 100% up-time, and have your server-side hub methods communicate with it that way.
One way for you to verify this is to debug the constructor of your hub class. You will notice that it is called for every client->server-side method call.

Reliably counting the number of client connections to a SignalR hub

I'm creating a web dashboard that will display the status of our test environments.
I use a hub to connect the browser to the server and have a background task that polls the status of the environment. I only want to perform this check if at least one client is connected.
My hub looks a little like this:
public class StatusHub : Hub
{
private static int connectionCount = 0;
public override Task OnConnected()
{
Interlocked.Increment(ref connectionCount);
return base.OnConnected();
}
public override Task OnReconnected()
{
Interlocked.Increment(ref connectionCount);
return base.OnReconnected();
}
public override Task OnDisconnected()
{
Interlocked.Decrement(ref connectionCount);
return base.OnDisconnected();
}
// other useful stuff
}
This mainly works but sometimes OnConnected is called but OnDisconnected is not.
One specific case is if I open chrome and type the address of the page but don't actually navigate to it. It seems Chrome is pre-fetching the page and connecting, but never disconnecting.
So two questions:
Is this a good approach to counting connections (I'm never going to be running in a web farm environment)?
Will these zombied connections from Chrome eventually timeout (I tried setting timeouts very low but still didn't get a disconnect)?
The events will always fire. If they don't, file a bug with repro steps on github. To get a more accurate number, you can store a hashset of connection ids and get the count from that.

Resources