如何在ASP.NET Core中获取SignalR Hub上下文?

52

我正在尝试使用以下内容获取枢纽的上下文:

var hubContext = GlobalHost.ConnectionManager.GetHubContext<SomeHub>();
问题在于GlobalHost未定义。我看到它是SignalR.Core dll的一部分。目前,我的项目.json文件中,在依赖项下有以下内容:
"Microsoft.AspNet.SignalR.Server": "3.0.0-*"

如果我添加最新可用的Core版本:

"Microsoft.AspNet.SignalR.Server": "3.0.0-*",
"Microsoft.AspNet.SignalR.Core" :  "2.1.2"

由于server和core存在冲突,我收到了很多错误。如果我将它们都更改为使用版本“3.0.0-*”,所有冲突都会消失,但无法找到GlobalHost。如果我删除Server,只使用Core版本2.1.2,那么GlobalHost可以正常工作,但是需要Server的所有其他内容显然都不起作用。

有什么想法吗?


类似问题的此答案提供了当前的解决方案。 - brichins
6个回答

107

IConnectionManager已不再在ASP.Net Core的SignalR中存在。
我一直使用HubContext来获取访问hub的权限。

public class HomeController : Controller
{
    private readonly IHubContext<LiveHub> _hubContext;

    public HomeController(IHubContext<LiveHub> hubContext)
    {
        _hubContext = hubContext;
    }

    public void SendToAll(string message)
    {
        _hubContext.Clients.All.InvokeAsync("Send", message);
    }
}
我正在使用 .net core 2.0.0 和 SignalR 1.0.0-alpha1-final。

你好!你能否提供一个示例,展示如何在IoC容器中注册HubContext类? - Andrew Nikolin
7
@AndrewNikolin,您不需要注册 HubContext。只需在 Configure 方法中引入您的 Hub。请使用以下代码:app.UseSignalR(routes => { routes.MapHub<LiveHub>("live"); }); 我认为通过 services.AddSignalR(); 自动注册了 HubContext - Soren
1
谢谢,那帮了我很多。但是我怎样才能从控制器之外访问HubContext呢?有没有办法在静态上下文中调用信令方法? - lenniep
2
@lenniep HubContext 可以在任何可用 IServiceProvider 的地方访问。你可以通过一些技巧在静态类中获取对 IServiceProvider 的访问权限,但这并不被推荐。 - Soren
2
针对.NET 5,等待_hubContext.Clients.All.SendAsync("yourmethod", yourparameters)。 - user2475096
显示剩余4条评论

25

Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager 是通过依赖注入注入的服务,您可以通过该服务获取hub上下文,例如:

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Infrastructure;
using Microsoft.AspNet.Mvc;

public class TestController : Controller
{
     private IHubContext testHub;

     public TestController(IConnectionManager connectionManager)
     {
         testHub = connectionManager.GetHubContext<TestHub>();
     }
 .....

6
这在RC1版本中能够运行,但在RC2版本中无法运行(我收到错误信息了)- 你知道如何修复吗? - Jakub Wisniewski
你好,你从哪里获取这些信息的?我搜索了几个小时也找不到文档。谢谢。 - SHM

9

要在后台服务中使用hub,除了控制器外,您还必须使用IHostedService接口,并通过DI获取hub。

public class MyBackgroundService : IHostedService, IDisposable
{
    public static IHubContext<NotifierHub> HubContext;

    public MyBackgroundService(IHubContext<NotifierHub> hubContext)
    {
        HubContext = hubContext;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        //TODO: your start logic, some timers, singletons, etc
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        //TODO: your stop logic
        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

然后您可以从任何代码中通过HubContext静态字段调用您的Hub:

MyBackgroundService.HubContext.Clients.All.SendAsync("UpdateData", myData).Wait();

了解更多关于IHostedService的信息: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1

你可以在MyBackgroundService中创建和启动一个定时器,并在ElapsedEvent中调用hub。


非常感谢。这正是我需要做的,以便从后台(hangfire)作业中让SignalR工作。 - Aaron

2

我需要能够从应用程序请求线程之外访问Hub上下文-因为我正在订阅NServicebus消息,并且需要在接收到消息时触发客户端函数。

以下是我解决问题的方法:

public static IServiceProvider __serviceProvider;

然后在启动配置期间

app.UseServices(services =>
        {
            __serviceProvider = new ServiceCollection()
            .BuildServiceProvider(CallContextServiceLocator.Locator.ServiceProvider);
        });

然后在vNext asp.net应用程序的任何其他地方(任何其他线程)

 var manager = Startup.__serviceProvider.GetRequiredService<IConnectionManager>();
            var hub = manager.GetHubContext<ChatHub>();

希望这能帮到您!

2

我在我的Startup.cs中添加了一些代码,用于获取ConnectionManager的引用,然后您可以在代码的任何地方随时使用它来执行GetHubContext。与Nimo的答案类似,但略有不同,也许更简单。

services.AddSignalR(options =>
{
    options.Hubs.EnableDetailedErrors = true;
});

var provider = services.BuildServiceProvider();

//Hold on to the reference to the connectionManager
var connManager = provider.GetService(typeof(IConnectionManager)) as IConnectionManager;

//Use it somewhere else
var hub = connManager.GetHubContext<SignalHub>();

你怎么才能在其他地方找到connManager呢?因为它不是静态的,所以你不是必须要注入或引用它吗? - stibay
5
截至最新版本构建,即0.0.2-alpha1-21709,该技术已不再有效。我在启动类中创建了一个名为IConnectionManager的静态变量。当它在另一个类中被引用时,虽然IHubContext可用,但hub.Clients.All.SendMessage("foo")无法将消息发送到客户端。 - Bill Shihara
@BillShihara - 你解决了你在这里提到的问题吗? - Glen Little

1
我正在查看SignalR 源代码,似乎IHubContext被注册为单例。
这意味着每次访问它时都会得到相同的实例。
这意味着你可以将其保存在静态变量中,并从任何地方使用。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHubContext<MyHub> hubContext)
{
    _staticVar = hubContext;
}

但是要注意 - 这是一种反模式。

我也想在NServiceBus处理程序中使用它。最终遵循了@RenanStr的建议。效果非常好。但是当你考虑它时,它并不与你所建议的“静态HubContext”有什么不同。 - Dharmesh Tailor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接