Autofac解决CQRS CommandDispatcher中的依赖关系

Art*_*ich 12 .net c# dependency-injection autofac cqrs

我正在尝试实现一个简单的CQRS应用程序示例.

这是我的"命令"部分的结构:

public interface ICommand
{
}

//base interface for command handlers
interface ICommandHandler<in TCommand> where TCommand: ICommand
{
    void Execute(TCommand command);
}

// example of the command
public class SimpleCommand: ICommand 
{
   //some properties
}

// example of the SimpleCommand command handler
public class SimpleCommandHandler: ICommandHandler<SimpleCommand>
{
    public void Execute(SimpleCommand command)
    {
       //some logic
    }

}
Run Code Online (Sandbox Code Playgroud)

这是界面ICommandDipatcher.它将命令分派给其处理程序.

public interface ICommandDispatcher
{
    void Dispatch<TCommand>(TCommand command) where TCommand : ICommand;
}
Run Code Online (Sandbox Code Playgroud)

这是默认实现,ICommandDispatcher主要问题是通过命令的类型获取必要的命令处理程序Autofac.

public class DefaultCommandDispatcher : ICommandDispatcher
{
    public void Dispatch<TCommand>(TCommand command) where TCommand : ICommand
    {
        //How to resolve/get object of the neseccary command handler 
        //by the type of command (TCommand)
        handler.Execute(command);
    }
}
Run Code Online (Sandbox Code Playgroud)

ICommandHanler在这种情况下,通过Autofac解决命令类型实现的最佳方法是什么?

谢谢!

Ste*_*ven 13

使用Autofac,您需要将其IComponentContext注入调度程序.这样您就可以回调容器来解析所需的命令处理程序:

public class AutofacCommandDispatcher : ICommandDispatcher
{
    private readonly IComponentContext context;

    public AutofacCommandDispatcher(IComponentContext context)
    {
        this.context = context;
    }

    public void Dispatch<TCommand>(TCommand command)
    {
        var handler = this.context.Resolve<ICommandHandler<TCommand>>();

        void handler.Execute(command);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以注册AutofacCommandDispatcher如下:

builder.RegisterType<AutofacCommandDispatcher>().As<ICommandDispatcher>();
Run Code Online (Sandbox Code Playgroud)

您可以一次注册所有命令处理程序,如下所示:

builder.RegisterAssemblyTypes(myAssembly)
    .AsClosedTypesOf(typeof(ICommandHandler<>));
Run Code Online (Sandbox Code Playgroud)

虽然有两个音符.首先,您可能将ICommandHandler<T>逆变量(使用in关键字)定义为因为Resharper这样说,但这对于命令处理程序来说是个坏主意.命令和命令处理程序之间总是存在一对一的映射,但是定义in关键字,表明可以有多个实现.

其次,在我看来,拥有一个命令调度程序是一个坏主意,因为这可以隐藏消耗类命令处理程序具有太多依赖关系这一事实,这表明违反了单一责任原则.此外,使用这样的调度程序推迟创建对象图的一部分(命令处理程序的一部分),直到命令被实际执行(与消费者被解析时相反).这使得验证容器配置变得更加困难.直接注入命令处理程序时,您确定可以在解析配置中的根类型时解析整个对象图.定义命令很容易但忘记创建相应的命令处理程序,因此您需要为此添加单元测试以检查每个命令是否具有相应的处理程序.如果您同时删除调度程序,则可以避免编写此类测试.