注册Autofac装饰只为一个通用的命令处理程序 [英] Register Autofac decorator for only one generic command handler
问题描述
我们有很多由Autofac开放式通用的方式注册通用命令处理程序。我们有装饰所有句柄情侣装饰。现在,我需要注册一个装饰只有一个命令处理程序,并不会影响到其他所有的命令处理程序。这是我上的尝试,但我似乎并没有得到登记的权利。
We have a lot of generic command handlers that are registered by Autofac in open-generic fashion. We have couple decorators that decorate all handles. Now I need to register a decorator for only one command handler and not affect all other command handlers. Here is my attempt on that, but I don't seem to get the registration right.
下面是简单的测试代码是类似于我们的代码:
Here is simple test code that is similar to our code:
我们有数百个命令的工作的这样
We have hundreds of commands working like this:
class NormalCommand : ICommand { }
// This command handler should not be decorated
class NormalCommandHandler : ICommandHandler<NormalCommand>
{
public void Handle(NormalCommand command) { }
}
和我想换ONLY TestCommandHandler
在装饰 TestCommandHandlerDecorator
And I would like to wrap ONLY TestCommandHandler
in decorator TestCommandHandlerDecorator
class TestCommand : ICommand { }
// And I would like to put decorator around this handler
class TestCommandHandler : ICommandHandler<TestCommand>
{
public void Handle(TestCommand command) { }
}
// This decorator should be wrapped only around TestCommandHandler
class TestCommandHandlerDecorator : ICommandHandler<TestCommand>
{
private readonly ICommandHandler<TestCommand> decorated;
public TestCommandHandlerDecorator(ICommandHandler<TestCommand> decorated)
{
this.decorated = decorated;
}
public void Handle(TestCommand command)
{
// do something
decorated.Handle(command);
// do something again
}
}
这是我如何注册我的组件:
That is how I register my components:
static class AutofacRegistration
{
public static IContainer RegisterHandlers()
{
var builder = new ContainerBuilder();
//Register All Command Handlers but not decorators
builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(AutofacRegistration)))
.Where(t => !t.Name.EndsWith("Decorator"))
.AsClosedTypesOf(typeof(ICommandHandler<>))
.InstancePerLifetimeScope();
// and here is the battle!
builder.RegisterType<TestCommandHandler>()
.Named<ICommandHandler<TestCommand>>("TestHandler")
.InstancePerLifetimeScope();
// this does not seem to wrap the decorator
builder.RegisterDecorator<ICommandHandler<TestCommand>>(
(c, inner) => new TestCommandHandlerDecorator(inner),
fromKey: "TestHandler")
.Named<ICommandHandler<TestCommand>>("TestHandler1")
.InstancePerLifetimeScope();
return builder.Build();
}
}
这就是我如何努力,以确认我得到
And this is how I try to confirm that I get correct instances of command handlers/decorators:
class AutofacRegistrationTests
{
[Test]
public void ResolveNormalCommand()
{
var container = AutofacRegistration.RegisterHandlers();
var result = container.Resolve<ICommandHandler<NormalCommand>>();
// this resolves correctly
Assert.IsInstanceOf<NormalCommandHandler>(result); // pass
}
[Test]
public void TestCommand_Resolves_AsDecorated()
{
var container = AutofacRegistration.RegisterHandlers();
var result = container.Resolve<ICommandHandler<TestCommand>>();
// and this resolves to TestCommandHandler, not decorated!
Assert.IsInstanceOf<TestCommandHandlerDecorator>(result); // FAILS!
}
}
随着评论说,装饰是没有得到应用,装饰注册将被忽略。
As the comment says, decorator is not getting applied, decorator registration is ignored.
所有的IDE如何注册这个装饰?什么?我做错了。
Any ides how to register this decorator?? What am I doing wrong?
推荐答案
要避免了人工登记@ trailmax的回答,您可以定义以下扩展方式:
To avoid the manual registration in @trailmax's answer you can define the following extension method:
public static class ContainerBuilderExtensions
{
public static void RegisterDecorator<TService, TDecorater, TInterface>(this ContainerBuilder builder,
Action<IRegistrationBuilder<TService, ConcreteReflectionActivatorData, SingleRegistrationStyle>> serviceAction,
Action<IRegistrationBuilder<TDecorater, ConcreteReflectionActivatorData, SingleRegistrationStyle>> decoratorAction)
{
IRegistrationBuilder<TService, ConcreteReflectionActivatorData, SingleRegistrationStyle> serviceBuilder = builder
.RegisterType<TService>()
.Named<TInterface>(typeof (TService).Name);
serviceAction(serviceBuilder);
IRegistrationBuilder<TDecorater, ConcreteReflectionActivatorData, SingleRegistrationStyle> decoratorBuilder =
builder.RegisterType<TDecorater>()
.WithParameter(
(p, c) => p.ParameterType == typeof (TInterface),
(p, c) => c.ResolveNamed<TInterface>(typeof (TService).Name))
.As<TInterface>();
decoratorAction(decoratorBuilder);
}
}
然后用这个像这样:
And then use this like so:
builder.RegisterDecorator<TestCommandHandler, TestCommandHandlerDecorator, ICommandHandler<TestCommand>>(
s => s.InstancePerLifetimeScope(),
d => d.InstancePerLifetimeScope());
这篇关于注册Autofac装饰只为一个通用的命令处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!