我有一个使用RabbitMQ(通过EasyNetQ)和SignalR的ASP.NET Core MVC项目。
接下来,我订阅了RabbitMQ消息,该消息应通过SignalR向客户端发送通知。
但是可悲的是,集线器始终解析为。
有趣的观察是,当应用程序仍在启动并且队列中仍然存在未确认的消息时,该服务实际上可以很好地解决。
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.RegisterEasyNetQ("host=localhost;virtualHost=/");
}
public void Configure(IApplicationBuilder app)
{
app.UseSignalR(route =>
{
route.MapHub<MyHub>("/mypath");
});
app.Use(async (context, next) =>
{
var bus = context.RequestServices.GetRequiredService<IBus>();
bus.SubscribeAsync<MyMessage>("MySubscription", async message =>
{
var hubContext = context.RequestServices
.GetRequiredService<IHubContext<MyHub>>();
// hubContext is null
await hubContext.Clients.All.SendAsync("MyNotification");
});
await next.Invoke();
});
}
我怀疑在
null
中注册订阅时可能做错了事,但是我似乎找不到任何有用的示例,因此这是我能想到的最好的示例。我在ASP.NET Core 3预览5上,我不知道这是否与我的问题有关。
所以问题是:如何在消息订阅处理程序中获取中心上下文?
更新
我已经检查了GetRequiredService docs,并且如果服务无法解析,则呼叫实际上应该抛出
app.Use
,但事实并非如此。它返回InvalidOperationException
,据我所知,这应该是不可能的(除非默认容器支持空值实例的注册)。 最佳答案
我已经设法通过实现IHostedService
来在this issue的帮助下解决了该问题。
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.RegisterEasyNetQ("host=localhost;virtualHost=/");
services.AddHostedService<MyHostedService>();
}
public void Configure(IApplicationBuilder app)
{
app.UseSignalR(route =>
{
route.MapHub<MyHub>("/mypath");
});
}
public class MyHostedService : BackgroundService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public ServiceBusHostedService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
var scope = _serviceScopeFactory.CreateScope();
var bus = scope.ServiceProvider.GetRequiredService<IBus>();
bus.SubscribeAsync<MyMessage>("MySubscription", async message =>
{
var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<MyHub>>();
await hubContext.Clients
.All
.SendAsync("MyNotification", cancellationToken: stoppingToken);
});
return Task.CompletedTask;
}
}