简单的喷油器打开通用装饰器 [英] Simple injector open generic decorators

查看:51
本文介绍了简单的喷油器打开通用装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to make use of some of the nice features in simple injector.

我目前在装饰器方面遇到问题,当我使用装饰器时,它们没有受到冲击

I am currently having problems with the decorators, they are not getting hit when I expect them too.

我正在这样注册它们:

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<>

I think I must be missing something as I am expecting that a call to ICommandHandler<CreateProductCommand> will invoke CreateValidFriendlyUrlCommandHandler<> and CreateProductValidationCommandHandler<> before running itself.

我尝试过这样的注册:

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)
 );

我想为 ICommandHandler< CreateProductCommand> CreateProductValidationCommandHandler CreateValidFriendlyUrlCommandHandler 时在类型 ICommandHandler< CreateProductCommand> c $ c>实现 ICommandHandler< CreateProductCommand> 可能会遇到一些循环引用。

As I thought registering a decorator for ICommandHandler<CreateProductCommand> on the type ICommandHandler<CreateProductCommand> when the CreateProductValidationCommandHandler and CreateValidFriendlyUrlCommandHandler implement ICommandHandler<CreateProductCommand> may well hit a bit of a circular reference.

没什么区别。

这是我的 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);
        }
    }
}


推荐答案

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

The problem is that Simple Injector will never be able to wrap an ICommandHandler<T> implementation with one of your decorators, because there is an unresolvable generic type TCommand. You would have noticed this if the Handle method of your decorators would call the decorated instance. For instance:

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 TCommand )。

This code won't compile, since the decorator's Handle method takes an CreateProductCommand argument, while the decorated instance takes a TCommand argument, which isn't specified (and nowhere is stated that CreateProductCommand is a TCommand).

实际上您根本没有创建装饰器。装饰器包装与实现的接口相同的实例。在实现 ICommandHandler< CreateProductCommand> 时,包装 ICommandHandler< TCommand> 。使此功能起作用的唯一方法是,当您明确指定 TCommand CreateProductCommand 时,如下所示:

In fact you didn't create a decorator at all. A decorator wraps an instance of the same interface that it implements. You wrap an ICommandHandler<TCommand> while you implement an ICommandHandler<CreateProductCommand>. The only way you would get this to work is when you explicitly specify the TCommand to be a CreateProductCommand, as follows:

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

不过,简单注入器无法猜测该 TCommand 应该是 CreateProductCommand ,这就是为什么您的装饰器没有被包裹的原因。

Still, there is no way for Simple Injector to 'guess' that this TCommand should be a CreateProductCommand and that's why your 'decorator' didn't get wrapped.

长话短说:抛弃 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

or remove the type constraint and allow handling any type of command, not only 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.

这篇关于简单的喷油器打开通用装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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