我正在尝试实现一个简单的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 } }
这是接口ICommandDipatcher.它向其处理程序分派命令.
public interface ICommandDispatcher { void Dispatch<TCommand>(TCommand command) where TCommand : ICommand; }
这是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); } }
通过Autofac的命令类型来解决ICommandHanler的实现的最佳方式是什么?
谢谢!
解决方法
使用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); } }
您可以注册AutofacCommandDispatcher,如下所示:
builder.RegisterType<AutofacCommandDispatcher>().As<ICommandDispatcher>();
您可以一次性注册所有的命令处理程序,如下所示:
builder.RegisterAssemblyTypes(myAssembly) .AsClosedTypesOf(typeof(ICommandHandler<>));
两个笔记.首先,您可能定义了ICommandHandler< T>因为Resharper这样说,作为违反(with关键字),但这对于命令处理程序来说是一个坏主意.在命令和命令处理程序之间始终存在一对一映射,但是定义in关键字,可以通信可以有多个实现.
第二,在我看来,使用命令调度程序是一个坏主意,因为这可以隐藏消息类的命令处理程序具有太多的依赖性,这表明违反了单一责任原则.此外,使用这样的调度器推迟创建对象图的一部分(命令处理程序的一部分),直到命令实际执行(与消费者解析时相反).这使得更难验证容器的配置.当直接注入命令处理程序时,您可以确定当您的配置中的根类型可以解决时,可以解决整个对象图.很容易定义一个命令,但忘记创建相应的命令处理程序,因此您需要添加单元测试来检查每个命令是否具有相应的处理程序.如果您一起删除调度程序,您可以节省自己编写此类测试的自己.