gpt4 book ai didi

c# - 使用 Autofac Autowiring 通用装饰器

转载 作者:行者123 更新时间:2023-11-30 22:24:07 25 4
gpt4 key购买 nike

我有两个装饰器:

class DbCommandWithTransactionHandlerDecorator<TCommand>
: IDbCommandHandler<TCommand> { ... }

class DbOptimisticConcurrencyRetryDecorator<TCommand>
: IDbCommandHandler<TCommand> { ... }

这些装饰器将事务管理和乐观并发重试功能添加到数据库命令。

我正在使用 Autofac 作为我的 IoC 容器。我想设置 Autofac,使其自动连接所有 IDbCommandHandler<>在程序集中找到,这样当我请求时说 IDbCommandHandler<CreateNewNotificationCommand> , 它会自动用第一个 DbCommandWithTransactionHandlerDecorator 装饰它, 然后是 DbOptimisticConcurrencyRetryDecorator .

我一直在尝试使用 Autofac 的 builder.RegisterGenericDecorator() 来获得它,但还没有成功。主要问题是装饰器需要一个“命名”参数才能工作。下面是最“接近”我想要实现的示例代码——但是主要缺陷是我仍然必须手动注册类型。

var builder = new ContainerBuilder();
var a = Assembly.GetExecutingAssembly();

// I need to find a way how these can be 'auto-wired',
// rather than having to manually wire each command.

builder.RegisterType<CreateNewNotificationCommandHandler>()
.Named<IDbCommandHandler<CreateNewNotificationCommand>>("command");
builder.RegisterType<CreateNewNotificationCommandHandler_2>()
.Named<IDbCommandHandler<CreateNewNotificationCommand_2>>("command");

builder.RegisterGenericDecorator(
typeof(DbCommandWithTransactionHandlerDecorator<>),
typeof(IDbCommandHandler<>),
fromKey: "command");

var container = builder.Build();
var handler1 =
container.Resolve<IDbCommandHandler<CreateNewNotificationCommand>>();
var handler2 =
container.Resolve<IDbCommandHandler<CreateNewNotificationCommand_2>>();
handler1.Handle(null); //these are correctly decorated
handler2.Handle(null); //these are correctly decorated

最佳答案

我确实设法通过反射找到了一个解决方法,虽然它有效但并不是很优雅。为了完整起见,我将在下面发布:

 public interface IDbCommandHandler<in TCommand>: IDbCommandHandlerStub
where TCommand : IDbCommand
{
void Handle(TCommand command);
}

public interface IDbCommandHandlerStub
{

}

private List<Type> getTypesThatImplementIDbCommandHandler(IEnumerable<Assembly> assemblyList)
{
List<Type> list = new List<Type>();
foreach (var a in assemblyList)
{
var matches = a.GetTypes().Where(t => typeof(IDbCommandHandlerStub).IsAssignableFrom(t));
list.AddRange(matches);
}
return list;
}

private void registerDbCommands(List<Type> dbCommandHandlerTypes, ContainerBuilder builder)
{
foreach (var t in dbCommandHandlerTypes)
{
var interfaces = t.GetInterfaces();
foreach (var i in interfaces)
{
builder.RegisterType(t).Named("dbCommand", i);
}

}
}


public void Test1()
{
ContainerBuilder builder = new ContainerBuilder();
var dbCommandHandlerTypes = getTypesThatImplementIDbCommandHandler(assemblies);
registerDbCommands(dbCommandHandlerTypes, builder);

builder.RegisterGenericDecorator(typeof(DbCommandWithTransactionHandlerDecorator<>),
typeof(IDbCommandHandler<>),
fromKey: "dbCommand", toKey:"dbCommandWithTransaction").SingleInstance();

builder.RegisterGenericDecorator(typeof(DbOptimisticConcurrencyRetryDecorator<>),
typeof(IDbCommandHandler<>),
fromKey: "dbCommandWithTransaction").SingleInstance();

var container = builder.Build();
var handler1 = container.Resolve<IDbCommandHandler<CreateNewNotificationCommand>>();

}

首先,我通过反射获得了所有实现IDbCommandHandler 的类型。然后,我将它们注册为它们实现的所有接口(interface)的命名类型,并为它们命名为“dbCommand”。

然后,我注册通用装饰器来装饰名为“dbCommand”的类型。此装饰器名为“dbCommandWithTransaction”,然后用于为并发重试注册另一个通用装饰器。

考虑到这是一次完成后就会被“遗忘”的事情,我准备采用此解决方法。但是,我在尝试其他 IoC 容器时遇到了 Simple Injector ,所有这些只需两行代码即可完成 - 从那时起就赢得了我的支持。

关于c# - 使用 Autofac Autowiring 通用装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12943877/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com