Access SignalR Hub without Constructor Injection

signalr call hub method from another class
signalr hub constructor injection
signalr server
asp.net signalr
asp net core signalr java client
signalr memory consumption
signalr multiple hubs
asp net signalr client

With AspNetCore.SignalR (1.0.0 preview1-final) and AspNetCore.All (2.0.6), how can I invoke a method on a hub in server code that is not directly in a Controller and is in a class that cannot be made via Dependency Injection?

Most examples assume the server code is in a Controller and should 'ask' for the hub via an injectable parameter in a class that will created by DI.

I want to be able to call the hub's method from server code at any time, in code that is not injected. The old SignalR had a GlobalHost that enabled this approach. Basically, I need the hub to be a global singleton.

Now, everything seems to be dependent on using Dependency Injection, which is introducing a dependency that I don't want!

I've seen this request voiced in a number of places, but haven't found a working solution.

Edit

To be more clear, all I need is to be able to later access the hubs that I've registered in the Configure routine of the Startup class:

app.UseSignalR(routes =>
        {
            routes.MapHub<PublicHubCore>("/public");
            routes.MapHub<AnalyzeHubCore>("/analyze");
            routes.MapHub<ImportHubCore>("/import");
            routes.MapHub<MainHubCore>("/main");
            routes.MapHub<FrontDeskHubCore>("/frontdesk");
            routes.MapHub<RollCallHubCore>("/rollcall");
            // etc.
            // etc.
        }); 

If I register them like this:

 services.AddSingleton<IPublicHub, PublicHubCore>();

it doesn't work, since I get back an uninitiated Hub.

No It's not possible. See "official" answer from david fowler https://github.com/aspnet/SignalR/issues/1831#issuecomment-378285819

How to inject your hubContext:

Best solution is to inject your hubcontext like IHubContext<TheHubWhichYouNeedThere> hubcontext into the constructor.

See for more details:

Call SignalR Core Hub method from Controller

Access SignalR Hub without Constructor Injection, All (2.0.6), how can I invoke a method on a hub in server code that is not directly in a Controller and is in a class that cannot be made via Dependency Injection? This pattern is called constructor injection. Another pattern is setter injection, where you set the dependency through a setter method or property. Simple Dependency Injection in SignalR. Consider the Chat application from the tutorial Getting Started with SignalR. Here is the hub class from that application:

Thanks to those who helped with this. Here's what I've ended up on for now...

In my project, I can call something like this from anywhere:

Startup.GetService<IMyHubHelper>().SendOutAlert(2);

To make this work, I have these extra lines in Startup.cs to give me easy access to the dependency injection service provider (unrelated to SignalR):

public static IServiceProvider ServiceProvider { get; private set; }
public static T GetService<T>() { return ServiceProvider.GetRequiredService<T>(); }
public void Configure(IServiceProvider serviceProvider){
  ServiceProvider = serviceProvider;
}

The normal SignalR setup calls for:

public void Configure(IApplicationBuilder app){
  // merge with existing Configure routine
  app.UseSignalR(routes =>
  {
    routes.MapHub<MyHub>("/myHub");
  });
}

I don't want all my code to have to invoke the raw SignalR methods directly so I make a helper class for each. I register that helper in the DI container:

public void ConfigureServices(IServiceCollection services){
  services.AddSingleton<IMyHubHelper, MyHubHelper>();
}

Here's how I made the MyHub set of classes:

using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;

public class MyHub : Hub { }

public interface IMyHubHelper
{
  void SendOutAlert(int alertNumber);
}

public class MyHubHelper : IMyHubHelper
{
  public IHubContext<MyHub> HubContext { get; }
  public MyHubHelper(IHubContext<MyHub> hubContext) 
  {
    HubContext = hubContext;
  }

  public void SendOutAlert(int alertNumber)
  {
    // do anything you want to do here, this is just an example
    var msg = Startup.GetService<IAlertGenerator>(alertNumber)

    HubContext.Clients.All.SendAsync("serverAlert", alertNumber, msg);
  }
}

SignalR HubContext, NET Core has a dependency injection framework that removes the Now, with access to an instance of IHubContext , you can call hub called from outside of the Hub class, there's no caller associated with the invocation. The SignalR hub is the core abstraction for sending messages to clients connected to the SignalR server. It's also possible to send messages from other places in your app using the IHubContext service. This article explains how to access a SignalR IHubContext to send notifications to clients from outside a hub.

This is a nice solution. In .NET Core 2.1 the service provider is disposed and you get cannot access disposed object. The fix is to create a scope:

   public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
    {
        ServiceProvider = serviceProvider.CreateScope().ServiceProvider;

Dependency Injection in SignalR, Dependency injection (DI) is a pattern where objects are not responsible Now call your class method in your application start up class you get in the SignalR creates them for you.by default SignalR expects a hub class to  I have a .Net Core 2.2 Web API for a chat app with a SignalR hub. I'd like to save the chats to the database (MySQL). At first, I thought I could inject my DbContext into the hub via dependency injection. But then I read that the hub is Singleton whereas the DbContext (when used via the AddDbContext helper) is Scoped.

Dependency Injection on SignalR - Blogs, SignalR integration provides dependency injection integration for SignalR hubs. Due to SignalR internals, there is no support in SignalR for per-request (This is similar to service location, but it's the only way to get a “per-hub” sort of scope. In a hub, authentication data can be accessed from the HubConnectionContext.User property. Authentication allows the hub to call methods on all connections associated with a user. For more information, see Manage users and groups in SignalR. Multiple connections may be associated with a single user. The following is an example of Startup

SignalR, In my application I want to be able to access my hub/clients anytime from the the title SignalR IHubContext<THub> "Singleton access" (Dependency GetRequiredService<> then I get an instance with no connections: If you differentiate an overload just by specifying different parameter types, your Hub class will compile but the SignalR service will throw an exception at run time when clients try to call one of the overloads. Reporting progress from hub method invocations. SignalR 2.1 adds support for the progress reporting pattern introduced in .NET 4.5.

IHubContext<THub> "Singleton access" (Dependency Injection , NET Core SignalR now support constructor dependency injection without extra It's also easy to gain access to a hub's context from outside the hub itself by  Now this is usable - I can call hubContext.Clients.All.SendAsync("something", args) and similar stuff and this works - BUT this is not a full hub so I have no access to private methods I have defined in ChatHub and I also don't have access to services injected in ChatHub's constructor - which is inconvenient but can be worked around;

Comments
  • Your usage scenario is cutting against the grain of both the new SignalR & ASP.NET Core design but if you must support this scenario, look at this truly evil code hack for an understanding of what you are up against. Maybe if you described your specific case to "call the hub's method from server code at any time" then there could be other approaches to solving that problem.
  • Actually tried that "evil hack" but it doesn't work with SignalR as the hubs need to be initialized correctly.
  • My whole point though is that in some classes where I need it, the class is not created via DI. How can I get it there? Or do I have to make all the parent classes pass down the reference to the hub from the Controller? That introduces too many dependencies!
  • @GlenLittle Ok than your question is more a DI Question. That's difficult to give you a general answer. There are a lot opinions about clean design. In one project we created a DI Factory as singleton which gives us the required instances. Other solution is (as you wrote) to pass all the required objects. But in the case you have to pass to much things I would think again about your design.
  • the idea of a DI factory would be okay for me, but it doesn't work with Hubs... or, I don't know how to connect to the Hubs' DI factory.
  • Let us continue this discussion in chat.
  • Your questions was "Access SignalR Hub without Injection" --> The answer is no (as we discussed) --> but now in your answer you do it with injection. This is not the answer of your question.
  • @Stephu You are correct, but it was constructor injection that is the roadblock. In my solution, the host code does not need to have a constructor that relies on injection. My question specifically says: "... in a class that cannot be made via Dependency Injection"
  • I've updated the title to more closely match the question.