Autofac 解析 CQRS CommandDispatcher 中的依赖项 [英] Autofac resolve dependency in CQRS CommandDispatcher

查看:29
本文介绍了Autofac 解析 CQRS CommandDispatcher 中的依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

This is a structure of my "Command" part:

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.它向其处理程序分派命令.

This is interface ICommandDipatcher. It dispatches a command to its handler.

public interface ICommandDispatcher
{
    void Dispatch<TCommand>(TCommand command) where TCommand : ICommand;
}

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

This is a default implementation of ICommandDispatcherand the main problem is to obtain the necessary command handler by the type of the command via 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 实现的最佳方法是什么?

What is the best way to resolve implementation of ICommandHanler by type of the command in that case via Autofac?

谢谢!

推荐答案

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

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>(TCommand command)
    {
        var handler = this.context.Resolve<ICommandHandler<TCommand>>();

        void handler.Execute(command);
    }
}

您可以按如下方式注册AutofacCommandDispatcher:

You can register the AutofacCommandDispatcher as follows:

builder.RegisterType<AutofacCommandDispatcher>().As<ICommandDispatcher>();

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

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

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

不过有两个注意事项.首先,您可能将 ICommandHandler 定义为逆变(使用 in 关键字),因为 Resharper 是这么说的,但这对命令处理程序来说是个坏主意.命令和命令处理程序之间始终存在一对一的映射关系,但定义 in 关键字表示可以有多个实现.

Two notes though. First of all, you probably defined the ICommandHandler<T> 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.

这篇关于Autofac 解析 CQRS CommandDispatcher 中的依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆