Autofac resolve dependency in CQRS CommandDispatcher

后端 未结 2 1741
小蘑菇
小蘑菇 2020-12-31 09:04

I\'m trying to implement a simple CQRS-application example.

This is a structure of my \"Command\" part:

public interface ICommand
{
}

//base interfa         


        
2条回答
  •  北海茫月
    2020-12-31 09:39

    With Autofac, you need to inject the IComponentContext into the dispatcher. This way you can call back into the container to resolve the required command handler:

    public class AutofacCommandDispatcher : ICommandDispatcher
    {
        private readonly IComponentContext context;
    
        public AutofacCommandDispatcher(IComponentContext context)
        {
            this.context = context;
        }
    
        public void Dispatch(TCommand command)
        {
            var handler = this.context.Resolve>();
    
            void handler.Execute(command);
        }
    }
    

    You can register the AutofacCommandDispatcher as follows:

    builder.RegisterType().As();
    

    And you can register all your command handlers in one go as follows:

    builder.RegisterAssemblyTypes(myAssembly)
        .AsClosedTypesOf(typeof(ICommandHandler<>));
    

    Two notes though. First of all, you probably defined the ICommandHandler as contravariant (with the in keyword) because Resharper said so, but this is a bad idea for command handlers. There is always a one-to-one mapping between a command and command handler, but defining the in keyword, communicates that there can be multiple implementations.

    Second, in my opinion, having a command dispatcher is a bad idea, because this can hide the fact that the consuming classes of command handlers have too many dependencies, which is an indication of a violation of the Single Responsibility Principle. Further more, using such a dispatcher postpones creation of part of the object graph (the part of the command handler) until the command is actually executed (opposed to when the consumer is resolved). This makes it harder to verify the container's configuration. When command handlers are injected directly, you know for sure that the whole object graph can be resolved when the root types in your configuration can be resolved. It's easy to define a command but forget to create the corresponding command handler, so you will need to add unit tests for this to check if each command has a corresponding handler. You can save yourself from having to write such test if you remove the dispatcher all together.

提交回复
热议问题