2
votes

I want to send message from Service A using SignalR when some event occures (for example, message from Service B received). So hub method needs to be called from some sort of handler, that not constructed using Dependency Injection. How I can do this?

So far, I tried and read about the following things:

  1. I can inject context into Controller and lead it to my handler. I probably can do that, but passing hub context from the top (controller class) to the bottom (handler class) is not the best approach, which adds a lot of dependencies to the classes that should not be aware of this context, so I would like to avoid that.
  2. I can inject my IHubContext in "any" class, but then, the thing is, how to get an instance of that class on my handler?
  3. Add Static method to class with injected context!? Well, that works until you have 1 client because with new client static property is going to be overwritten.

So I cannot imagine, how handler can use dependency injected IHubContext.

Probably, someone did that before and have an example of how to truly inject context into any class.

Thank you in advance and any additional information will be provided, if necessary.

1
At which point you are constructing your handler? I guess, the handler is not the starting point, otherwise, you could add it to the DI in Startup class, using AddSingleton or other Add* methods. Then resolve it using the ServiceProvider which will automatically resolve the IHubContext dependency on my handler. Can you please elaborate with more code?Shahzad Hassan
@ShahzadHassan After some thoughts. Yes, a handler is not an entry point. Handler created once per service launch, so multiple clients can connect to that service and go through that handler. On the other hand, an instance of the hub is created per method call. I guess I should remove that line with "ideal solution" from the question.Sviatoslav V.
choices are limited in that case I am afraid. DI works from top to bottom, but inner dependencies are resolved first, so if A has a dependency on B and B has a dependency on C. It will resolve the dependencies for B first and then goes to A. I guess, you are newing up the handler at some point inside the controller? Why not implement an interface for the handler and inject it in the controller? That way it will be resolved by the DIShahzad Hassan
@ShahzadHassan No, I am not newing handler inside the controller. Basically, the handler will be reconstructed only when service re-launched. Also, I cannot implement and inject interface for handler, because handler has some other dependencies that is not constructed by DI.Sviatoslav V.

1 Answers

1
votes

Answer 1

Here is one possible solution. Implement a factory pattern. Create a factory that knows how to create your handler. Inject the IHubContext in the factory. You can use a few approaches that way:

  1. Construct the Handler by passing in the IHubContext
  2. Create a public property in the Handler and set the IHubContext
  3. Create a method in the Handler and pass the IHubContext as a parameter

You can decide whichever approach suits you. Inject that factory in the controller via DI, and get the handler using the factory method. That way you are not exposing the IHubContext. Please see the code below

public interface IHandlerFactory
{
   Handler CreateHandler();
}

public class HandlerFactory : IHandlerFactory
{
    private IHubContext _hubContext;

    public HandlerFactory(IHubContext context)
    {
        _hubContext = context;
    }
    public Handler CreateHandler()
    {
        return new Handler(param1, param2, _context);
    }    
}

Then in the entry point, controller/service, inject the factory via DI

public class MyController : Controller
{
    private Handler _handler;

    public MyController(IHandlerFactory factory)
    {
        _handler = factory.CreateHandler();
    }
}

Then you can use that _handler in the other methods. I hope this helps.

Answer 2

Another possible solution is to use IHostedService if it's possible at all for you. Please see a solution to a GitHub issue, provided by David Fowler here, that I think somewhat relevant to your scenario.