简单的喷油器打开通用装饰器 [英] Simple injector open generic decorators
问题描述
我正在尝试使用简单注射器中的一些不错的功能。
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> $ c注册一个装饰器当
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屋!