Home > database >  Do I need dependency injection to automatically register my message handlers?
Do I need dependency injection to automatically register my message handlers?

Time:01-31

I have RegisterMessageHandlers that register message handler per message name. I want to automatically find and register all handlers through reflection. I can annotate each message with MessageAttribute (like shown below) and get the message name through reflection as well. The problem is when I want to instantiate a handler via Activator I have to provide all the dependencies in the constructor.

My solution is to register all instances with DI and pass IServiceProvider to MainManagerClass(IServiceProvider provider) and then use ActivatorUtilities.CreateInstance(handlerType) to instantiate each discovered handler through reflection.

But, then I read that there is DI and service locator which is antipattern and it's not very clear when one becomes the other.

So, I think I need a DI in order to accomplish what I want. Or do I?

public class MainManagerClass
{
    private Dictionary<string, MessageHandler> _handlers;

    private void RegisterMessageHandlers()
    {
        _messageHandlers["msg1"] = new MessageHandler1(new Service1());
        _messageHandlers["msg2"] = new MessageHandler2(new Service1(), new Service2());
    }
}
   
public class MessageHandler1 : MessageHandler<Message1>
{
    public MessageHandler1(IService1 service){}
}

public class MessageHandler2 : MessageHandler<Message2>
{
   public MessageHandler1(IService1 service1, IService2 service2){}
}

public abstract class MessageHandler<T> : MessageHandler
{
}

public abstract class MessageHandler
{
}

[Message("msg1")]
public class Message1
{
}

CodePudding user response:

If you don't want to add interface and keep abstract class as in your example - you can register your handlers like that:

builder.Services.AddTransient<MessageHandler<Message1>, MessageHandler1>();
builder.Services.AddTransient<MessageHandler<Message2>, MessageHandler2>();

And then if you inject MessageHandler<Message1> in your controller for instance, MessageHandler1 will be resolved as well as other dependencies (IService1 in your case).

CodePudding user response:

I think I still don't get your question but I hope this will be helpfull for you. Anyway, I followed Jaroslav's answer and your comment to create MessageHandlerFactory object then I changed your code a bit to cover both scenarios but you need the message type to resolve its handler from the service provider plus, If you want to register all handlers automatically, you should use reflection at startup, find all objects that inherit from IMessageHandler<T>, and register them to DI or use packages like Scrutor.

public class MessageHandlerFactory
{
    private IServiceProvider _serviceProvider;

    public IMessageHandler<T> ResolveHandler<T>()
    {
        return _serviceProvider.GetRequiredService<IMessageHandler<T>>();
    }
}
   
public class MessageHandler1 : IMessageHandler<Message1>
{
    public MessageHandler1(IService1 service){}
}

public class MessageHandler2 : IMessageHandler<Message2>
{
   public MessageHandler2(IService1 service1, IService2 service2){}
}

public interface IMessageHandler<T> 
{
}


public class Message1
{
}

public class Message2
{
}

builder.Services.AddScoped<IMessageHandler<Message1>, MessageHandler1>();
builder.Services.AddScoped<IMessageHandler<Message2>, MessageHandler2>();
  • Related