停止Autofac模块注册已注册的组件

问题描述 投票:6回答:2

我有一个Autofac模块,它在Load覆盖中具有以下(修剪)逻辑:

protected override void Load(ContainerBuilder builder)
    {
        foreach (var componentType in allTypesInAllAvailableAssemblies) // Set elsewhere
        {
            var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>)));
            if (handlerInterfaces.Any())
                builder.RegisterType(componentType).As(handlerInterfaces);
        }
    }

这是寻找任何声明自己的消息处理程序并将其注册到它实现的所有IMessageHandler接口的类。

我想要做的是,如果组件已经注册,则不注册该组件。作为奖励,如果我可以更新现有注册以解决消息处理程序接口(如果尚未解决),那将是理想的。

为了参数,可以假设此代码将在所有其他类型已注册后运行(包括可能的消息处理程序候选)

我过去曾使用AttachToComponentRegistration覆盖进行注册操作,但在这种情况下看起来并不像它有用。

这是可能的还是我应该重新考虑我的设计并强制插件明确声明他们的处理程序?

c# autofac
2个回答
8
投票
builder.RegisterType(componentType)
    .As(handlerInterfaces)
    .PreserveExistingDefaults();

将工作。


1
投票

不幸的是,没有一种优雅的方式来做你想要的。 Autofac容器及其构建器是“黑盒子”,不允许您仔细查看已有的容器。

注册组件两次没有任何害处,除非您的注册依赖于订单(BAD,BAD,BAD)。第二次注册只会用新的覆盖旧注册。

我严重质疑这段代码,因为它完全取决于如何初始化allTypesInAllAvailableAssemblies。如果它真的是你系统中的每一种类型,那么它就是一个废话,就像什么会解决,比如说,IDisposable。如果你有几个不同的实现,例如IConfigurator,你将无法控制哪一个最终注册,无论你是在检查已注册的内容还是只是覆盖注册;它完全取决于列表中第一个(或最后一个)结束的类。

我唯一能想到的就是使用一点Linq来确保您注册的类型列表是唯一的:

protected override void Load(ContainerBuilder builder)
{
    foreach (var componentType in allTypesInAllAvailableAssemblies.OfType<Type>().Distinct()) // Set elsewhere
    {
        var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>)));
        if (handlerInterfaces.Any())
            builder.RegisterType(componentType).As(handlerInterfaces);
    }
}

这将保证构建器之前从未看到componentType的每个实例,在此foreach循环的范围内。这意味着,鉴于这是用于构建容器的唯一模块,并且每个Container仅构建一次并且从不更新,系统中的每个组件都将在任何给定的容器中注册一次。常见的接口,如IDisposable,IEnumerable,IComparable,IComparer等,试图解决它们将毫无价值;他们将解析为具有该接口的最后一个类的实例。

如果你必须验证一个接口从未被注册,或者这个代码在使用ContainerBuilder更新()一个现有容器时也能正常工作,那就停止你正在做的事情,因为你要创造一个绝望的混乱,你将永远不会能够妥善保养。

© www.soinside.com 2019 - 2024. All rights reserved.