【问题标题】:SignalR hub resolves to null inside RabbitMQ subscription handler in ASP.NET CoreSignalR 集线器在 ASP.NET Core 的 RabbitMQ 订阅处理程序中解析为 null
【发布时间】:2019-10-15 02:10:21
【问题描述】:

我有一个带有 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 docs,如果服务无法解析,调用实际上应该抛出InvalidOperationException,但它没有。它返回null,据我所知,这是不可能的(除非默认容器支持注册空值实例)。

【问题讨论】:

    标签: asp.net-core rabbitmq signalr easynetq


    【解决方案1】:

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

    【讨论】:

    • 嗨,我有一个问题,为什么我们不需要将 While 循环或 Timer Callback 放在总线的 ExecuteAsync 中。SubscribeAsync(); ?提前谢谢你。
    • @Armin Shoeibi:由于该服务已注册为托管服务,因此不需要循环来防止应用程序停止。总线消息订阅是由 EasyNetQ 发出的回调。
    猜你喜欢
    • 1970-01-01
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2022-06-17
    • 1970-01-01
    相关资源
    最近更新 更多