如何在ASP.NET Core 2.1 RC的Program.cs中获取SignalR Hub上下文
我明白你现在的困境——在完整.NET框架里用GlobalHost很顺手,但到了ASP.NET Core这套依赖注入的体系里,在Program.cs这种没有注入上下文的地方发消息确实有点绕。别担心,咱们一步步解决这个问题:
核心思路
在ASP.NET Core中,GlobalHost已经被移除了,取而代之的是通过依赖注入容器获取IHubContext<T>。因为你的OnReceiveEvent是静态方法,我们可以在启动WebHost时把Hub上下文保存为静态字段,这样就能在事件处理方法里直接使用了。
具体实现步骤
1. 在Program类中添加静态字段保存Hub上下文
在Program.cs里,先声明一个静态字段来存储UserInterfaceHub的上下文:
using InterfaceModule.Hubs; using Microsoft.AspNetCore.SignalR; namespace YourNamespace // 替换成你的实际命名空间 { class Program { // 静态字段保存Hub上下文 private static IHubContext<UserInterfaceHub> _uiHubContext; // 其他代码... } }
2. 启动WebHost时获取并保存Hub上下文
修改你启动WebHost的代码,在Build()之后、Start()之前,从服务容器中获取IHubContext<UserInterfaceHub>并赋值给静态字段:
var webHost = CreateWebHostBuilder(args) .UseKestrel() .UseUrls("http://0.0.0.0:" + appProperties.HostPort.ToString().Trim()) .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .Build(); // 从服务容器中获取Hub上下文(GetRequiredService确保获取不到时抛出异常,方便排查) _uiHubContext = webHost.Services.GetRequiredService<IHubContext<UserInterfaceHub>>(); webHost.Start();
3. 在OnReceiveEvent中发送消息
现在你可以在静态的OnReceiveEvent方法里直接使用_uiHubContext来向客户端发送消息了。注意:不要直接调用Hub类的实例方法(比如SwitchUI),因为Hub的实例是为每个连接单独创建的,外部无法直接复用实例方法。你可以把SwitchUI里的逻辑直接搬过来,或者把业务逻辑抽成独立的服务:
static async Task<MessageResponse> OnReceiveEvent(Message message, object userContext) { // 直接向所有客户端发送消息,和SwitchUI里的逻辑一致 await _uiHubContext.Clients.All.SendAsync("ReceiveEvent", "事件触发啦!"); // 如果需要解析消息内容,比如从message.Body中提取数据 // var eventContent = Encoding.UTF8.GetString(message.Body); // await _uiHubContext.Clients.All.SendAsync("ReceiveEvent", eventContent); return MessageResponse.Completed; }
额外优化建议
如果你的应用规模会变大,建议把发送SignalR消息的逻辑封装成一个独立的服务,让代码更符合依赖注入的设计原则,也更容易维护:
public class UiNotificationService { private readonly IHubContext<UserInterfaceHub> _hubContext; public UiNotificationService(IHubContext<UserInterfaceHub> hubContext) { _hubContext = hubContext; } public async Task SendSwitchUiMessage(string message) { await _hubContext.Clients.All.SendAsync("ReceiveEvent", message); } }
然后在Startup.cs的ConfigureServices里注册这个服务:
services.AddScoped<UiNotificationService>();
之后在Program.cs里获取这个服务来使用即可。
内容的提问来源于stack exchange,提问作者Jason

