2

I am using SignalR v2.41, which is old, but I have to use it since I am also limited to using an old version of MVC. That aside, I am also using FluentScheduler to send targeted messages to clients at intervals.

Problem is, I am keeping a dictionary of user connections in my Hub:

public class MyHub: Hub
{
    public Dictionary<string, User> Connections { get; set; }

    public MyHub()
    {
        Connections = new Dictionary<string, User>();
    }

    public override Task OnConnected()
    {
        // add connection
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        // remove connection
        return base.OnDisconnected(stopCalled);
    }
}

Now in the FluentScheduler code I need to get hold of the hub for the connections list so I know which connection to send what to:

public class MyJob : IJob
{
    public void Execute()
    {
        var hub = new DefaultHubManager(GlobalHost.DependencyResolver).ResolveHub("MyHub") as MyHub;
        foreach (var conn in hub.Connections)
        {
            foreach (var msg in msgs)
            {
                hub.Clients.Client(conn.Key).send(msg);
            }
        }
    }
}

Problem is, the hub instance I get using var hub = new DefaultHubManager(GlobalHost.DependencyResolver).ResolveHub("MyHub") as MyHub; is different from the one to which clients connect, as this one never has any connections.

How can I get the right hub instance?

Colton Scottie
  • 807
  • 1
  • 8
  • 22

1 Answers1

0

The new is always a new instance so you will never get the hub where your clients are connected because you creating a new hub.

You should resolve the hub like this:

static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();

You also can check this question.

Edit: Since you need to send messages to specific users, I would recommend to implement a class to add and remove the connections, or even better, map users to groups.

It's recommend that you always inject IHubContext than the Hub. Quote from a SignalR developer on github:

You generally shouldn't resolve the Hub out of DI. If you need to share code between your Hub and some other component, I'd suggest using either IHubContext or putting the shared code in a separate DI service instead.

Also you should not add the Hub as a singleton:

SignalR expects the Hub to be created separately for each message. You need to add it as a Transient service if you want your Hub to be in DI.

and

Because instances of the Hub class are transient, you can't use them to maintain state from one method call to the next. Each time the server receives a method call from a client, a new instance of your Hub class processes the message. To maintain state through multiple connections and method calls, use some other method such as a database, or a static variable on the Hub class, or a different class that does not derive from Hub.

More documentation about Hub object lifetime.

Kiril1512
  • 3,231
  • 3
  • 16
  • 41
  • Yep I tried this, however it gets me the context interface only, not my custom class, which has the `Connections` property. – Colton Scottie Sep 15 '20 at 21:01
  • @ColtonScottie For what you need the connections if in your code you want to send to all connected users? – Kiril1512 Sep 16 '20 at 08:17
  • That is just some sample code, I will need to send to specific users. That was the whole point of my question. – Colton Scottie Sep 16 '20 at 10:21
  • I've been trying that for hours, unfortunately Autofac does not let me resolve the object that stores the connections because I do not have a `HttpContext` (in the FluentScheduler code). Well its not part of MVC so how could I... – Colton Scottie Sep 16 '20 at 11:46
  • The same way you inject the `IHubContext` you will inject the connections class and call the methods that will return you the dictionary or the connection id of a specific user. – Kiril1512 Sep 16 '20 at 11:57
  • I don't inject the IHubContext, its automatic by SignalR. Anyway I have asked that question more specifically here: https://stackoverflow.com/questions/63919569/how-to-access-autofac-singleton-instance-without-httpcontext – Colton Scottie Sep 16 '20 at 11:58
  • ok, but the question `How to get hold of the right SignalR hub in other part of application?` was answered here. Close this question then. – Kiril1512 Sep 16 '20 at 14:01