SignalR hub resolves to null inside RabbitMQ subsc

2019-08-15 08:17发布

I have an ASP.NET Core MVC project with RabbitMQ (by means of EasyNetQ) and SignalR.

Next, I have a subscription on a RabbitMQ message that should send a notification to the client via SignalR.

But sadly, the hub always resolves to null.

An interesting observation is that when the application is still starting and there are still unacknowledged messages in the queue, the service actually resolves just fine.

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

I suspect that perhaps I'm doing something wrong with regards to registering the subscription inside an app.Use but I can't seem to find any useful examples so this was the best I could figure.

I'm on ASP.NET Core 3 preview 5, I don't know if that has anything to do with my problem.

So the question is: how do I get the hub context inside the message subscription handler?

UPDATE

I've checked the GetRequiredService docs and the call should actuall throw an InvalidOperationException if the service couldn't be resolved, but it doesn't. It returns null, which as far as I can tell, shouldn't be possible (unless the default container supports registration of null-valued instances).

1条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-15 08:56

I've managed to solve the issue with help from this issue by implementing an IHostedService instead.

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;
    }
}
查看更多
登录 后发表回答