我有一个使用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;
    }
}

10-08 04:48