calling the Caller method in SignalR hub outside the hub context - asp.net

I have a question in my mind about the Caller method of SignalR. In the hub method we can call a client side function like this.
Clients.Caller.addContosoChatMessageToPage(name, message);
but when i use to call it from outside the hub context it is not found or not implemented?? like this..
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.Caller.reportProgress(recordCount,totalCount);
Can someone enlighten me in this part or is there other way to implement it..
by now i use to implement this
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.User(CurrentUser.Usernm).reportProgress(recordCount,totalCount);
but now we are not claim based authentication so it will be a problem if the same usernm are logged..

Outside of the hub, there obviously is no caller because the server is the one who initiates.
If you are worried about unique user names, you'll need to implement a custom IUserIdProvider, or you need to manage connection ids per user in some other way. Then you could call
context.Clients.Client(connectionId).reportProgress();
which would be unique.

Related

Is it possible to create a global context available throughout the web application when i receive a message from Azure Service Bus?

I have a web api application which subscribes to a topic in azure service bus during startup.
When I receive a message from service bus, is it possible to establish a context similar to HttpContext that is available across the application methods?
There's not enough here to give you any exact direction, but in general, this just involves scopes. If whatever is listening for messages is has a "scoped" lifetime, then you can inject your context directly. If, as is more likely, it has a singleton lifetime, then you must instead inject IServiceProvider and retrieve your context via:
using (var scope = provider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<MyContext>();
// do something with context
}
You can only use the context within the scope, so do not try to do something like store it in an instance variable or something.

SignalR Hub: Calling same method with same parameters on multiple clients

I have an existing service that notifies a large number of clients when an event occurs. It uses a long polling mechanism that I rolled myself. I'm exploring replacing that mechanism with a signalr hub, and have a prototype working. But it has a pretty significant inefficiency that feels like there should be a solution to, but I'm not finding it.
I understand the idea of groups in signalr, and groups are obviously intended to prevent this inefficiency, but there is a reason that I cannot use groups. I hope it suffices to say that I need to call the same client method, with the same parameter values, on many clients using each client's ConnectionId. I can explain why if necessary, but it's really beside the point.
Assume I have a list of 200 ConnectionId's and I need to call the same method on each of them passing the same object parameter. If I simply iterate through the ConnectionId's calling Clients.Client(ConnectionId).clientMethod(param), I presume that the param object would be serialized 200 times.
Is there a way to serialize the parameter(s) one time, then invoke the client method using the already-serialized parameters?
UPDATE
I've found a github issue that sounds related (maybe even this exact issue) at Allow to Send Json Strings without duplicate Serialization. It appears that the functionality was added to signalr, but the github issue doesn't say anything about how to do it, and I can't find anything regarding it in the signalr docs.
UPDATE 2
In the github issue referenced above, the new functionality was implemented for PersistentConnection only -- not hubs. With persistent connections, when sending a parameter of type ArraySegment, signalr assumes it to be pre-serialized and sends it as-is without serializing it.
For some reason, this was not implemented for hubs, although it would be useful for hubs for the same reason it was useful for persistent connections.
Store all connectionId's in a Static List<string> atOnConnected` event and use the following,
Static List<string> allconnections = new List<string>();
public override Task OnConnected()
{
allconnections.Add(Context.ConnectionId);
return base.OnConnected();
}
Public void YourServerMethod(params)
{
Clients.Clients(allConnections).clientMethod(params)
}

How to pass data to Signalr hub class

I have some global data that stored in session["Gdata"] so that I can access these information any time I want. However, I can't access session["Gdata"] in signalr hub class.
Is there any way to access session in hub class ?
You can't use session in Signalr hub class, see this link
No access to the Session information through SignalR Hub. Is my design is wrong?
There are some solutions to your problem. You can use Standard ASP.NET security to store your global information.
You can store the data you want using this code
FormsAuthentication.SetAuthCookie("string contain your data", false);
and you can retrieve your data using this code
string GlobalData = Context.User.Identity.Name;

Getting specific hub instance associated with a specific SignalRConnectionId

Getting a reference to the client using the SignalRConnectionId is pretty simple via the GlobalHost class. Is there a way to get a reference to a hub instance associated with that client/connection? In other words, given the client connection Guid, can I get a reference to a hub instance that's talking to that client? The reason I want to do this is so I can invoke an instance method on the hub from somewhere else in the server.
It is not possible to get a Hub instance from outside of the SignalR Hub pipeline or the Hub itself.
Hubs are ephemeral in SignalR. Generally a new Hub is instantiated for each invocation, and then disposed immediately after.
This means that a single WebSocket connection can have an arbitrary number of associated Hub instances over its lifetime. Moreover, unless there is an ongoing invocation, it's unlikely that there is even an associated Hub in existence.
I would suggest replicating the Hub instance method you want to call with a static method that takes an IHubContext as a parameter. You can get the IHubContext using GlobalHost.ConnectionManager.GetHubContext.

SignalR hosting on separate appPool

My web application have a chat app module built on SignalR hub.
The app will have 1000+ concurrent users. I want to host the Chat Module on a separate app pool to separate it from my main application so that SignalR does not bottleneck my main application.
I'm not sure how to go about it. I've built a simple Chat system (much like Google Talk) tied to my Main Web project using Hub class and client side code resides in Site Master since it will be common across the application.
i also want to be able to call Hub method outside the Hub class. For example, an admin might assign certain task to an user from admin panel. So, from the Controller method after completing service operation (task assignment) successfully, I want to send a SignalR message to that particular user. Should I be using Hub or Persistence connection to achieve both the goal? Host SignalR on a different port? I'd appreciate some guidance on this. Thanks!
Not that I think you necessarily have to do this, but I can understand the desire to separate. To do this you would have to have your MVC application call hub methods as if it was a SignalR client itself. You can either do this by putting separate methods on the same hub or by adding a secondary hub which exists solely for this kind of inter-app communication.
I would probably use the latter approach of having a second hub because you can secure it differently. If you go this route, you would simply get the HubContext for the primary hub and make whatever calls you want/fire whatever signals you want to it. That might look something like this:
public MyInterAppCommunicationHub : Hub
{
public void SendSystemAlert(string message)
{
HubContext myPrimaryHubContext = GlobalHost.ConnectionManager.GetHubContext<MyPrimaryHub>();
myPrimaryHubContext.Clients.systemAlert(message);
}
}

Resources