SignalR hub 在 ASP.NET Core 中的 RabbitMQ 订阅处理程序中解析为 null

SignalR hub resolves to null inside RabbitMQ subscription handler in ASP.NET Core

我有一个 ASP.NET 核心 MVC 项目,其中包含 RabbitMQ(通过 EasyNetQ)和 SignalR。

接下来,我订阅了一条 RabbitMQ 消息,该消息应通过 SignalR 向客户端发送通知。

但遗憾的是,集线器总是解析为 null

一个有趣的观察是,当应用程序仍在启动并且队列中仍有未确认的消息时,服务实际上解析得很好。

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

我怀疑我在 app.Use 中注册订阅方面可能做错了,但我似乎找不到任何有用的示例,所以这是我能想到的最好的。

我正在 ASP.NET Core 3 预览版 5,我不知道这是否与我的问题有关。

所以问题是:如何在消息订阅处理程序中获取集线器上下文?

更新

我已经检查了 GetRequiredService docs,如果服务无法解析,调用实际上应该抛出 InvalidOperationException,但事实并非如此。据我所知,它 returns null 应该是不可能的(除非默认容器支持空值实例的注册)。

this issue 的帮助下,我通过实施 IHostedService 来解决问题。

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