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

标签 c# decorator autofac

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

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

我们有数百个命令是这样工作的:

class NormalCommand : ICommand { }

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

我只想在装饰器 TestCommandHandlerDecorator 中包装 TestCommandHandler

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

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

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

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

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

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

任何ides如何注册这个装饰器?我做错了什么?

最佳答案

在用头敲打键盘足够多次后,我找到了解决问题的方法:

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

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

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

关于c# - 仅为一个通用命令处理程序注册 Autofac 装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18000522/

相关文章:

asp.net-mvc-4 - 在 ASP.Net MVC 4 和 Autofac 中注册全局过滤器

asp.net - 了解如何从数据库加载 Nop Commerce 设置

c# - 强制转换 C# 参数?

c# - sql server current_timestamp 与 c# datetime.now

python - 如何为属性的延迟初始化创建装饰器

java - 装饰器模式,编译器不允许类型传播

asp.net - 无法加载文件或程序集 Autofac,版本 = 3.3.0.0

sql-server - BLToolKit 保存 null 而不是 0

c# - 如何在连接表(Fluent NHibernate)上使用带有属性(列)的 NHibernate ManyToMany

class - 编写 TypeScript 装饰器以始终将类方法绑定(bind)到 'this'