仅为一个通用命令处理程序注册Autofac装饰器

tra*_*max 5 c# decorator autofac

我们有许多通用命令处理程序,由Autofac以开放式通用方式注册.我们有几个装饰器来装饰所有手柄.现在我需要为一个命令处理程序注册一个装饰器,而不是影响所有其他命令处理程序.这是我的尝试,但我似乎没有正确注册.

这是与我们的代码类似的简单测试代码:

我们有数百个命令如下:

class NormalCommand : ICommand { }

// This command handler should not be decorated
class NormalCommandHandler : ICommandHandler<NormalCommand>
{
    public void Handle(NormalCommand command) { }
}
Run Code Online (Sandbox Code Playgroud)

而且我想TestCommandHandler在装饰器中包装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
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我注册我的组件的方式:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我尝试确认我得到命令处理程序/装饰器的正确实例的方法:

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!
    }
}
Run Code Online (Sandbox Code Playgroud)

正如评论所说,装饰器没有被应用,装饰器注册被忽略.

任何想法如何注册这个装饰?我究竟做错了什么?

tra*_*max 3

在用头撞键盘足够多次之后,我对我的问题有了某种解决方案:

static class AutofacRegistration
{
    public static IContainer RegisterHandlers()
    {
        var builder = new ContainerBuilder();

        builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(AutofacRegistration)))
            .AsClosedTypesOf(typeof(ICommandHandler<>))
            .InstancePerLifetimeScope();

        builder.RegisterType<TestCommandHandler>()
               .Named<ICommandHandler<TestCommand>>("TestHandler")
               .InstancePerLifetimeScope();

        // this works!
        builder.Register(c => new TestCommandHandlerDecorator(c.ResolveNamed<ICommandHandler<TestCommand>>("TestHandler")))
               .As<ICommandHandler<TestCommand>>()
               .InstancePerLifetimeScope();

        return builder.Build();
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我没有使用 Autofac 的装饰器功能并手动包装装饰器。因此,如果装饰器中的依赖项数量增加,我需要更新容器以解决所有必需的依赖项。

如果您知道更好的解决方案,请告诉我!