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