从中心外部发送消息

SignalR 中心是用于向连接到 SignalR 服务器的客户端发送消息的核心抽象。 你也可以使用 IHubContext 服务从应用中的其他位置发送消息。 本文介绍如何访问 SignalRIHubContext 以从中心外部向客户端发送通知。

注意

IHubContext 用于将通知发送到客户端,而非用于调用 Hub 上的方法。

查看或下载示例代码(如何下载)

获取 IHubContext 实例

在 ASP.NET Core SignalR 中,你可以通过依赖项注入来访问 IHubContext 实例。 你可以将 IHubContext 实例注入控制器、中间件或其他 DI 服务。 使用该实例向客户端发送消息。

注意

这与 ASP.NET 4.x SignalR 不同,后者使用 GlobalHost 提供对 IHubContext 的访问。 ASP.NET Core 有一个依赖项注入框架,因此无需使用此全局单一实例。

在控制器中注入 IHubContext 实例

通过将 IHubContext 实例添加到构造函数,可以将其注入控制器:

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

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

获权访问 IHubContext 实例后,就像在中心本身一样调用客户端方法:

public async Task<IActionResult> Index()
{
    await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: {DateTime.Now}");
    return View();
}

在中间件中获取 IHubContext 实例

访问中间件管道中的 IHubContext,如下所示:

app.Use(async (context, next) =>
{
    var hubContext = context.RequestServices
                            .GetRequiredService<IHubContext<ChatHub>>();
    //...
    
    if (next != null)
    {
        await next.Invoke();
    }
});

注意

当从 Hub 类外部调用客户端方法时,没有与该调用关联的调用方。 因此,无法访问 ConnectionIdCallerOthers 属性。

从 IHost 获取 IHubContext 实例

从 Web 主机访问 IHubContext 对于与 ASP.NET Core 之外的区域集成很有用,例如,使用第三方依赖项注入框架:

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder => {
                    webBuilder.UseStartup<Startup>();
                });
    }

注入强类型 HubContext

若要注入强类型 HubContext,请确保中心继承自 Hub<T>。 使用 IHubContext<THub, T> 接口而不是 IHubContext<THub> 进行注入。

public class ChatController : Controller
{
    public IHubContext<ChatHub, IChatClient> _strongChatHubContext { get; }

    public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext)
    {
        _strongChatHubContext = chatHubContext;
    }

    public async Task SendMessage(string user, string message)
    {
        await _strongChatHubContext.Clients.All.ReceiveMessage(user, message);
    }
}

有关详细信息,请参阅强类型中心

在泛型代码中使用 IHubContext

注入的 IHubContext<THub> 实例可以强制转换为 IHubContext,而无需指定泛型 Hub 类型。

class MyHub : Hub
{ }

class MyOtherHub : Hub
{ }

app.Use(async (context, next) =>
{
    var myHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyHub>>();
    var myOtherHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyOtherHub>>();
    await CommonHubContextMethod((IHubContext)myHubContext);
    await CommonHubContextMethod((IHubContext)myOtherHubContext);

    await next.Invoke();
}

async Task CommonHubContextMethod(IHubContext context)
{
    await context.Clients.All.SendAsync("clientMethod", new Args());
}

此操作在以下情况下十分有用:

  • 编写不引用应用正在使用的特定 Hub 类型的库。
  • 编写可应用于多个不同 Hub 实现的泛型代码

其他资源