c# - 如何使用 structuremap asp.net mvc 注册可选装饰器或带有可选参数的装饰器?

标签 c# asp.net-mvc decorator cqrs structuremap3

我在我的应用程序中实现了 CQRS 方法,深受这篇精彩文章的影响:https://cuttingedge.it/blogs/steven/pivot/entry.php?id=9 .我的命令和处理程序代码设置与文章相同,并且该部分运行良好。当我尝试实现装饰器类来处理命令验证时,我的问题就来了。简单的命令处理界面如下所示:

public interface ICommand
{
}

public interface ICommandHandler<TCommand>
{
    void Handle(TCommand command);
}

然后对于验证装饰器,我有:

public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : CommandBase
{
    private readonly ICommandHandler<TCommand> _decoratedCommandHandler;
    private readonly ICommandValidator<TCommand> _commandValidator;

    public ValidationCommandHandlerDecorator(ICommandHandler<TCommand> decoratedCommandHandler, ICommandValidator<TCommand> commandValidator)
    {
        _decoratedCommandHandler = decoratedCommandHandler;
        _commandValidator = commandValidator;
    }

    public void Handle(TCommand command)
    {
        if (_commandValidator != null)
        {
            var validationResult = _commandValidator.Validate(command);

            if (validationResult != null)
            {
                command.Success = false;
                command.Errors = validationResult;
                return;
            }
        }

        _decoratedCommandHandler.Handle(command);
        command.Success = true;
    }
}    

它使用一个接口(interface)来定义验证器:

public interface ICommandValidator<TCommand>
{
    IEnumerable<string> Validate(TCommand command);
}

CommandBase是一个简单的基类,允许我存储命令的成功或失败以及失败时发生的错误。我更喜欢这种方法作为抛出异常的替代方法。所有命令都将继承这个基类。

public abstract class CommandBase : ICommand
{
    public bool Success { get; set; }
    public IEnumerable<string> Errors { get; set; }
}

这一切都连接到结构映射注册表中的 IoC 容器:

public class CommandRegistry : Registry
{
    public CommandRegistry()
    {
        Scan(s =>
        {
            s.AssemblyContainingType<CommandBase>();
            s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>));
            s.ConnectImplementationsToTypesClosing(typeof(ICommandValidator<>));
            s.WithDefaultConventions();

            For(typeof(ICommandHandler<>)).DecorateAllWith(typeof(ValidationCommandHandlerDecorator<>));
        });
    }
}

现在,由于我为每个 ICommandHandler 注册了装饰器,如果我有一个不需要验证器且未定义验证器的命令,ICommandValidator<TCommand> _commandValidator ValidationCommandHandlerDecorator<TCommand>的私有(private)领域找不到类,因为它当然不存在,并且总是会抛出一个结构图错误:

"No default Instance is registered and cannot be automatically determined for type 'ICommandValidator' There is no configuration specified for ICommandValidator"

有没有办法在结构图中定义ValidationCommandHandlerDecorator得到构造,以便在不存在时使用某种类型的默认验证器,而不必依赖类中的容器或必须创建 IValidateableCommandHandler<TCommand>使用验证器处理命令的接口(interface)?

谢谢。

最佳答案

如果以后有人遇到这个问题,我想到的解决方案是添加一个 DefaultCommandValidator 类作为 Null Object 模式类:

public class DefaultCommandValidator<TCommand> : ICommandValidator<TCommand> where TCommand : CommandBase
{
    public IEnumerable<string> Validate(TCommand command)
    {
        return Enumerable.Empty<string>();
    }
}

然后将这一行添加到结构图注册表:

For(typeof(ICommandValidator<>)).Use(typeof(DefaultCommandValidator<>));

我不知道这个结构映射语法实际上只有在找不到 ICommandValidator<TCommand> 的具体实现时才会使用默认实例。 .现在,如果我没有验证器,我只是不添加一个和 DefaultCommandValidator<TCommand>实例用于返回一个空的/成功的验证。

关于c# - 如何使用 structuremap asp.net mvc 注册可选装饰器或带有可选参数的装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31814770/

相关文章:

c# - ASP.NET MVC Controller 单元测试失败

python - 在类方法和子类方法上使用 python 装饰器

javascript - vscode 是否支持 decorator after export default?如何启用此功能?

c# - c++ 和 c# sin 函数大值的不同结果

c# - 在 ASP.NET MVC 应用程序中缓存 "dictionary-like"DB 实体

c# - 无法在 .NET 4 MVC 4 应用程序中加载文件或程序集系统,版本 = 2.0.5.0

python - 用于包装尝试的通用装饰器除了在 python 中?

c# - visual studio 网站 - 有很多随机错误,但仍在 build 中?

c# - XOR二进制数c#

c# - F# 对象树语法