2

我正在尝试利用简单注射器中的一些不错的功能。

我目前在装饰器方面遇到问题,当我期望它们时,它们也没有受到打击。

我正在像这样注册它们:

container.RegisterManyForOpenGeneric(
      typeof(ICommandHandler<>),
      AppDomain.CurrentDomain.GetAssemblies());

container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateValidFriendlyUrlCommandHandler<>),
      context => context.ServiceType == typeof(ICommandHandler<CreateProductCommand>)
 );

 container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateProductValidationCommandHandler<>),
      context => context.ServiceType == typeof(ICommandHandler<CreateProductCommand>)
 );

我想我一定错过了一些东西,因为我期望调用ICommandHandler<CreateProductCommand>将在CreateValidFriendlyUrlCommandHandler<>运行CreateProductValidationCommandHandler<>之前调用。

我尝试过这样的不同注册:

container.RegisterManyForOpenGeneric(
      typeof(ICommandHandler<>),
      AppDomain.CurrentDomain.GetAssemblies());

container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateValidFriendlyUrlCommandHandler<>),
      context => context.ImplementationType == typeof(CreateProductCommandHandler)
 );

 container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateProductValidationCommandHandler<>),
      context => context.ImplementationType == typeof(CreateProductCommandHandler)
 );

正如我所想的那样,当and实现可能会遇到一些循环引用时ICommandHandler<CreateProductCommand>,为类型注册一个装饰器。ICommandHandler<CreateProductCommand>CreateProductValidationCommandHandlerCreateValidFriendlyUrlCommandHandlerICommandHandler<CreateProductCommand>

但改变这一点并没有什么不同。

这是我的CreateProductValidationCommandHandler<TCommand>

public class CreateProductValidationCommandHandler<TCommand> 
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;
    private readonly IValidationService validationService;

    public CreateProductValidationCommandHandler(
        ICommandHandler<TCommand> decorated,
        IValidationService validationService)
    {
        this.decorated = decorated;
        this.validationService = validationService;
    }

    public void Handle(CreateProductCommand command)
    {
        if (!validationService.IsValidFriendlyName(
            command.Product.ProductFriendlyUrl))
        {
            command.ModelStateDictionary.AddModelError(
                "ProductFriendlyUrl", 
                "The Friendly Product Name is not valid...");

            return;
        }

        if (!validationService.IsUniqueFriendlyName(
            command.Product.ProductFriendlyUrl))
        {
            command.ModelStateDictionary.AddModelError(
                "ProductFriendlyUrl", 
                "The Friendly Product Name is ...");

            return;
        }
    }
}

这是我的CreateValidFriendlyUrlCommandHandler<TCommand>

public class CreateValidFriendlyUrlCommandHandler<TCommand>
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(ICommandHandler<TCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        if (string.IsNullOrWhiteSpace(
            command.Product.ProductFriendlyUrl))
        {
            command.Product.ProductFriendlyUrl = 
                MakeFriendlyUrl(command.Product.Name);
        }
    }
}
4

1 回答 1

3

问题是 Simple Injector 永远无法ICommandHandler<T>用您的装饰器之一包装实现,因为存在无法解析的泛型类型TCommandHandle如果您的装饰器的方法会调用decorated实例,您会注意到这一点。例如:

public class CreateValidFriendlyUrlCommandHandler<TCommand>
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<TCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // This won't compile since CreateProductCommand and
        // TCommand are not related.
        this.decorated.Handle(command);
    }
}

这段代码不会编译,因为装饰器的Handle方法接受一个CreateProductCommand参数,而decorated实例接受一个TCommand未指定的参数(并且没有说明CreateProductCommand是 a TCommand)。

事实上,您根本没有创建装饰器。装饰器包装了它实现的同一接口的实例。你ICommandHandler<TCommand>在实现一个ICommandHandler<CreateProductCommand>. 让它工作的唯一方法是当你明确指定TCommand为 aCreateProductCommand时,如下所示:

ICommandHandler<CreateProductCommand> handler = 
    new CreateValidFriendlyUrlCommandHandler<CreateProductCommand>(
        new CreateProductCommandHandler()
    );

尽管如此,Simple Injector 还是无法“猜测”这TCommand应该是 a CreateProductCommand,这就是为什么您的“装饰器”没有被包装的原因。

长话短说:放弃TCommand

public class CreateValidFriendlyUrlCommandHandler
    : ICommandHandler<CreateProductCommand>
{
    private ICommandHandler<CreateProductCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<CreateProductCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // logic here
    }
}

或者使用类型约束使其通用:

   public class CreateValidFriendlyUrlCommandHandler<TCommand>
        : ICommandHandler<TCommand>
        where TCommand : CreateProductCommand
    {
        private ICommandHandler<TCommand> decorated;

        public CreateValidFriendlyUrlCommandHandler(
            ICommandHandler<TCommand> decorated)
        {
            this.decorated = decorated;
        }

        public void Handle(TCommand command)
        {
            // logic here
        }
    }

或删除类型约束并允许处理任何类型的命令,而不仅仅是CreateProductCommand.

Note that if you are defining many decorators that can only handle one specific type of command handler, you might want to reconsider your strategy. There might be a problem in your design.

于 2012-11-18T08:20:43.747 回答