无需构造函数注入即可访问 SignalR Hub

Access SignalR Hub without Constructor Injection

使用 AspNetCore.SignalR (1.0.0 preview1-final) 和 AspNetCore.All (2.0.6),我如何在不直接在控制器中的服务器代码中调用集线器上的方法并且处于无法通过依赖注入实现的 class 中?

大多数示例假定服务器代码在控制器中,并且应该通过 DI 创建的 class 中的可注入参数 'ask' 用于集线器。

我希望能够在未注入的代码中随时从服务器代码调用集线器的方法。旧的 SignalR 有一个支持这种方法的 GlobalHost。基本上,我需要集线器是一个全局单例。

现在,一切似乎都依赖于使用依赖注入,这引入了我不想要的依赖!

我在很多地方都看到过这个请求,但还没有找到可行的解决方案。

编辑

更清楚地说,我需要的是以后能够访问我在 Startup class 的 Configure 例程中注册的集线器:

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.
        }); 

如果我这样注册它们:

 services.AddSingleton<IPublicHub, PublicHubCore>();

它不起作用,因为我找回了一个未启动的集线器。

不,这不可能。请参阅 david fowler "official" 的回答 https://github.com/aspnet/SignalR/issues/1831#issuecomment-378285819

如何注入你的 hubContext:

最好的解决方案是像 IHubContext<TheHubWhichYouNeedThere> hubcontext 一样注入你的 hubcontext 进入构造函数。

查看更多详情:

感谢为此提供帮助的人。这是我现在结束的...

在我的项目中,我可以从任何地方调用这样的东西:

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

为了完成这项工作,我在 Startup.cs 中添加了这些额外的行,让我可以轻松访问依赖注入服务提供程序(与 SignalR 无关):

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

正常的 SignalR 设置需要:

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

我不希望我的所有代码都必须直接调用原始 SignalR 方法,因此我为每个方法创建了一个帮助程序 class。我在 DI 容器中注册了那个助手:

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

以下是我制作 classes MyHub 集的方法:

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);
  }
}

这是一个很好的解决方案。在 .NET Core 2.1 中,服务提供者已被处置,您无法访问已处置的对象。解决方法是创建一个范围:

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