Autofac 过滤器解析了 IEnumerable 实现
Posted
技术标签:
【中文标题】Autofac 过滤器解析了 IEnumerable 实现【英文标题】:Autofac filter resolved IEnumerable implementations 【发布时间】:2018-05-09 08:48:45 【问题描述】:在autofac中解析IEnumerable
时是否可以过滤依赖关系?
我有多个接口实现(在下面的示例中为IHandler
),这些实现是在独立项目中使用 Autofac 模块定义和注册的。我希望能够在父类型中解析时过滤实现(在下面的示例中为Processor
)。
IHandler
实现可以注入Processor
并在ctor
中过滤,但这需要解析所有实现,无论是否需要它们,这是浪费。
public interface IHandler
public class Handler1 : IHandler
public class Handler2 : IHandler
public class Handler3 : IHandler
public class Processor
public IEnumerable<IHandler> Handlers;
public Processor(IEnumerable<IHandler> handlers)
Handlers = handlers;
static void Main(string[] args)
var builder = new ContainerBuilder();
builder.RegisterType<Handler1>().As<IHandler>();
builder.RegisterType<Handler2>().As<IHandler>();
builder.RegisterType<Handler3>().As<IHandler>();
builder.RegisterType<Processor>().AsSelf();
var container = builder.Build();
var processor = container.Resolve<Processor>();
由于一次只能解析 1 个密钥,因此我使用密钥的尝试无效:
[Flags]
public enum HandlerType
One = 1,
Two = 2,
Three = 4
builder.RegisterType<Handler1>().Keyed<IHandler>(HandlerType.One);
builder.RegisterType<Handler2>().Keyed<IHandler>(HandlerType.Two);
builder.RegisterType<Handler3>().Keyed<IHandler>(HandlerType.Three);
var enabledHandlers = HandlerType.One | HandlerType.Three;
builder.RegisterType<Processor>().AsSelf()
.WithParameter(ResolvedParameter.ForKeyed<IEnumerable<IHandler>>(enabledHandlers));
【问题讨论】:
也许这有帮助:autofaccn.readthedocs.io/en/latest/faq/select-by-context.html 您希望根据哪些条件过滤这些处理程序? 感谢@UmutOzel,我也许可以使用ResolvedParameter
使其工作。
@Steven 我应该从配置文件中说得更清楚,例如<add key="Handlers" value="1,3" />
...
【参考方案1】:
我建议使用Meta<T>
和Lazy<T>
implicit relationship types 允许处理器在运行时读取配置并控制所有这些。这也将允许您在不同的条件下进行不同的过滤,或者完全关闭过滤,而无需更改任何键。
使用元数据注册处理程序,而不是作为键控服务...
builder.RegisterType<Handler1>()
.As<IHandler>()
.WithMetadata("type", HandlerType.One);
builder.RegisterType<Handler2>()
.As<IHandler>()
.WithMetadata("type", HandlerType.Two);
builder.RegisterType<Handler3>()
.As<IHandler>()
.WithMetadata("type", HandlerType.Three);
更新您的处理器以采用IEnumerable<Meta<Lazy<IHandler>>>
并在构造期间或稍后需要处理程序时进行过滤,您的电话。
public class Processor
private readonly IHandler[] _handlers;
public Processor(IEnumerable<Meta<Lazy<IHandler>>> handlers)
this._handlers =
handlers
.Where(h => h.Metadata["type"] == HandlerType.One || h.Metadata["type"] == HandlerType.Three)
.Select(h => h.Value.Value)
.ToArray();
进入构造函数的每个项目都是Meta<Lazy<IHandler>>
:
Meta<T>
有一个要查询的 Metadata
字典,Value
将是 Lazy<IHandler>
。
在您调用 Value
属性之前,Lazy<T>
不会解析/构造处理程序,因此它不会很昂贵或导致您不想要的解决方案。
所以item.Value.Value
将是已解析的IHandler
(如您在上面的LINQ 中所见)。
Where
过滤器中的内容可以基于配置或其他任何内容。但真正的胜利在于,如果您仍然需要在其他地方解析所有处理程序...
public OtherHandlerConsumer(IEnumerable<IHandler> handlers)
...这仍然有效。如果它们都被键控,你就不能这样做。此外,您可以根据需要向注册添加尽可能多的元数据,甚至可以定义更强大的strongly typed metadata,以便您可以更明智地决定所需的处理程序。
【讨论】:
非常有趣的方法,我没有考虑使用Lazy
来减轻解决可能不使用的依赖项的成本。【参考方案2】:
如果您可以在容器设置阶段提供适当的过滤器(就像您在示例代码中所做的那样),您可以将您的 Processor
类型注册更改为以下内容:
builder.RegisterType<Processor>().AsSelf()
.WithParameter((p, c) => p.Name == "handlers",
(p, c) => new[]
c.ResolveKeyed<IHandler>(HandlerType.One),
c.ResolveKeyed<IHandler>(HandlerType.Three)
);
您需要使用的值可以从您想要的任何地方获取,也可以从配置文件中获取。
【讨论】:
这与我使用的解决方案很接近,但会根据配置过滤已解析的类...谢谢【参考方案3】:由于注册的处理程序基于配置开关,这意味着选定的处理程序不会在运行时更改。这与根据一些 runtime 条件选择处理程序非常不同。因此,我提出了类似的建议:
var handlerIds = ConfigurationManager.AppSettings["Handlers"].Split(',');
if (handlerIds.Contains("1")) builder.RegisterType<Handler1>().As<IHandler>();
if (handlerIds.Contains("2")) builder.RegisterType<Handler2>().As<IHandler>();
if (handlerIds.Contains("3")) builder.RegisterType<Handler3>().As<IHandler>();
if (handlerIds.Contains("4")) builder.RegisterType<Handler4>().As<IHandler>();
// etc
builder.RegisterType<Processor>().AsSelf();
【讨论】:
这可能对某些人有用,但在我的情况下,handler
s 是“在独立项目中使用 Autofac 模块定义和注册的”,这意味着它们独立于配置等。
我很困惑。在之前的评论中,您描述了它们来自配置。
是的,在示例中,IHandler
使用的配置是一个配置文件。但是每个IHandler
impl 都是一个独立的项目,具有最少的依赖和自注册 AutofacModule。抱歉,我应该更清楚一点。
有了这个解释,这并没有真正改变我的答案,除了每个 if 检查操作系统都移到了一个模块中。你仍然不需要键控注册,惰性或元。以上是关于Autofac 过滤器解析了 IEnumerable 实现的主要内容,如果未能解决你的问题,请参考以下文章
Autofac - ASP.NET Core 中的动作过滤器中的属性注入