I have a simple demo with only 1 client and the server. I can send messages back and forth, very trivial stuff.
The server Hub has a timer which sends a message to the client(s) every 1000 milliseconds. Now I have a button, where when clicked, sends a message to the server (via signalR).
Problem:
When the button is clicked (and the message sent to the server), the Hub is instantiated each time (I read about the SignalR lifecycle here).
Of course, when the Hub is instantiated the Timer is also instantiated. So the side effect (ie. bug) that I am seeing is that messages are being send to the client from multiple Hub instances.
What I would like:
I would like the client to receive messages (from the Timer that is running on the Hub), but only 1 set of messages from a single Hub (latest Hub instance?). I do not want simultaneous/multiple messages that were spawned from each Hub that was instantiated.
But perhaps I am doing something drastically wrong in design here.
You shouldn´t set the timer in the hub instance because they are re-created on every request.
Just create a Singleton class to handle the timer and actions. Then access that singleton from your hub instance.
The singleton instance will persist during the whole live cycle of your application, thus you will create only one timer.
To avoid concurrency problems, your singleton should be Lazy
Related
I have a self hosted webApi project in a desktop C# application. This uses Microsoft.Owin.Hosting.WebApp.
I have a Hub derived class that has a send and a receive from an angular client.
The hub is instanced by the WebApp.start. I find that it is short lived. When the client sends a message, the hub is instanced and then disposed. I need to send message to the client, but I don't have an instance of the hub to send a message in the other direction.
At one point, I was holding a reference to the instance (as in memory leak) and I could get a message to the client.
The client shows as it is always connected. No disconnected messages.
What am I missing?
You should not hold this instance by yourself and you shold never create an instance by yourself.
Read the details about the hub onject life time here:
https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server#hub-object-lifetime
In the case you need to send a message to the connected clients you need to use GetHubContext.
Example:
var context = GlobalHost.ConnectionManager.GetHubContext<yourHub>();
context.Clients.All.Send("Something");
(In the case you are using core signalr read: Call SignalR Core Hub method from Controller)
When the browser says long polling but the debugger in the constructor of hub class does not hit. What is the problem?
Basically what I want is everytime the long polling happens, I also want a particular functionality like a database call to be executed.
poll requests are receive channel (i.e. are only used by the server to send data to the client if there is any) and as the result they don't cause instantiating hubs. However you can override the ProcessRequest method on the server side - it is being called for each HTTP request the server is receiving so you can do whatever you want there.
I am writing a web application an it uses SignalR. On the server c#, I have two hubs.
It really does need to be two otherwise I would just merge them and solve the problem.
The problem that I am having, is that while I am aware that SignalR client side, hubs
will share a connection. The issue I am having, is that when I close the browser, or call stop on the client. Only 1 of my server side OnDisconnect(bool stopCalled) events will fire.
I somehow expected that both would fire when the client disconnects.
Am I being silly or doing something wrong perhaps?
Any info will be greatly appreciated.
Louis
I think the problem you are experiencing might be due to you not hooking up any event handlers (i.e. client hub methods) to the Hub that isn't triggering OnDisconnected. If this really is the cause, OnConnected also shouldn't be triggered on the same Hub.
The SignalR Hubs API Guide for the JavaScript client goes into some detail in one of its "notes" about why this is the case. Here's the relevant quote:
Note: Normally you register event handlers before calling the start method to establish the connection. If you want to register some event handlers after establishing the connection, you can do that, but you must register at least one of your event handler(s) before calling the start method. One reason for this is that there can be many Hubs in an application, but you wouldn't want to trigger the OnConnected event on every Hub if you are only going to use to one of them. When the connection is established, the presence of a client method on a Hub's proxy is what tells SignalR to trigger the OnConnected event. If you don't register any event handlers before calling the start method, you will be able to invoke methods on the Hub, but the Hub's OnConnected method won't be called and no client methods will be invoked from the server.
Every reference to the OnConnected method applies equally to the OnDisconnected method.
You can add an arbitrary event handler to your Hub before calling start() on the client to ensure that OnConnected and OnDisconnected get called on that Hub. It doesn't matter if the event handler will never be called. Ex:
$.connection.myHub.client.thisWillNeverBeCalled = function () { };
$.connection.hub.start()//...
As long as the first line is there, OnConnected and OnDisconnected should be called on MyHub.
In the end, after almost 2 days troubles shooting and browsing the web for answers.
I ended up just merging the two hubs into a single hub. It might not be the most elegant solution, but it did get the job done and progress can now be made on the rest of the app.
Thanks for the advice though from everyone :)
Louis
Have started using SignalR. Would like to clear few queries regarding how SignalR have implemented broadcasting basically how server is able to initiate the Communication ?
1> In normal scenario whenever we request for a let say .aspx page, the server renders the page and returns the reponse back to the client and the things is done
But How SignalR is able to continously able to execute in Background/Async in case of Ticker demo available on the ASP.net site.
I googled little bit and found IRegisteredObject is one of the way where the the object which need to be excuted continously need to register with HostingEnvironment but for that the class have to implement the IRegisteredObject interface but in case of ticker demo none of the class implements the IRegisteredObject interface.
Am I mssing something over here or SignalR uses totally different technique ?
SignalR utilizes 4 transports through which it handles data from the server. Only one transport is used at a time but SignalR has 4 to ensure server/client communication on a wide variety of devices/browsers. Here's the transports and a short technical description:
Long Polling, to receive data it uses an ajax request whose response is not released until there is data available on the server, once the server returns data on the held onto response the client then creates another request and waits for the next batch of data. To send data it creates a second ajax request.
Forever Frame, uses iframes through which the server pushes down javascript text which is then executed in the iframe, the iframe then propagates the execution up to the parent page which then handles the data. To send data SignalR uses ajax requests.
Server Sent Events, uses the EventSource object. Supported in nearly everything but IE. The EventSource object opens up a one way pipe through which the server can pump data through, allowing the client to receive data in real time. To send data SignalR uses ajax requests.
Web Sockets, uses the built-in browser WebSocket object which opens up a single, bi-directional channel through which data can be received and sent.
That's the essence of each of SignalR's transports, you can see an hour presentation in which David Fowler and Damian Edwards create a Lite version of SignalR here. It essentially highlights how SignalR works under the covers.
I have an MVC project, with multiple pages.
I have a long running process, which updates the client on its progress. However, this update is sent only to a single client, instead of broadcasting to all.
Clients.Client(ConnectionId).sendMessage(msg);
In my layout.cshtml, this is how I connect to the hub
var serverHub = $.connection.notifier;
window.hubReady = $.connection.hub.start(function () { });
The problem is, when I navigate to another page, I no longer receive the messages from signalr, because the connection id has changed.
How should I workaround this issue, such that my signalr hub can still send messages to a single client, while the client navigates from page to page.
You will want to create a server mapping of users to connection id's. See: SignalR 1.0 beta connection factory.
You will want to let your users persist past an OnDisconnected event and when they connect with a different connection Id you can continue pumping data down to them.
So the thought process could be as follows:
Page loads, SignalR connection is instantiated
Once connection is fully started call => TryCreateUser (returns a user, whether it existed or it was created).
Long Running process Starts
Client changes pages -> SignalR connection stops
New Page loads, new SignalR connection is instantiated
Once connection is fully started see if you have a cookie, session, or some type of data representing who you are => TryCreateUser(userData) (returns the user you created on the last page).
Data continues pumping down to user.
Note: if you take an authentication approach you will have to be authenticated prior to starting a connection and that data cannot change during the lifetime of a SignalR connection, it can only be created/modified while the connection is in the disconnected state.