首页 > 解决方案 > SignalR 集线器在 ASP.NET Core 的 RabbitMQ 订阅处理程序中解析为 null

问题描述

我有一个带有 RabbitMQ(通过 EasyNetQ)和 SignalR 的 ASP.NET Core MVC 项目。

接下来,我订阅了一条 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 preview 5 上,我不知道这是否与我的问题有关。

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

更新

我检查了GetRequiredService 文档InvalidOperationException,如果服务无法解析,调用实际上应该抛出一个,但它没有。它返回null,据我所知,这是不可能的(除非默认容器支持注册空值实例)。

标签: asp.net-corerabbitmqsignalreasynetq

解决方案


我已经设法通过实施一个代替这个问题来解决这个问题。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;
    }
}

推荐阅读