autofac - Autofac - 基于注册提供者的动态解析
问题描述
我在为我的问题找到合适的解决方案时遇到问题,即:
让我们考虑工作流程:
- 申请开始
- 主要组件在 Autofac 中注册
- 应用程序加载插件程序集并在其中注册模块
- 正在构建容器
- 插件处理逻辑运行
插件可以添加自己的控制器。为了正确处理这个问题,我必须准备接口,该接口将为我提供自定义控制器的类型:
interface ICustomControllerProvider
{
IEnumerable<Type> GetControllerTypes();
}
基于上述,我的应用程序知道如何将指定类型集成为控制器。所有控制器也被定义为服务,所以 Autofac 处理它们的创建,所以......
问题:我想避免两次指定自定义控制器类型
public PluginControllerProvider : ICustomControllerProvider
{
public IEnumerable<Type> GetControllerTypes()
{
// 1st type specification
// controller types are specified here, so they could be integrated with app
yield return typeof(ControllerX);
yield return typeof(ControllerY);
}
}
public class PluginModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<PluginControllerProvider>().As<ICustomControllerProvider>();
// 2nd type specification
// controllers have to be register in module as well
builder.RegisterType<ControllerX>();
builder.RegisterType<ControllerY>();
}
}
有什么方法可以由 Autofac 管理,我只在其中指定了ControllerX
它们?我尝试通过提供自定义注册源和解析来实现这一点,但是我无法根据from提供的参数进行解析ControllerY
PluginControllerProvider
ICustomControllerProvider
ICustomControllerProvider
IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)
IRegistrationSource
解决方案
Autofac 不提供注入使用 Autofac注册的类型列表的能力。您必须自己通过使用生命周期范围注册表来获得它。
在我讨论如何解决这个问题之前,我可能应该注意:
- 从 DI 的角度来看,列出注册的类型并不是一件正常的事情。这就像列出 MVC 应用程序中的所有控制器一样——您通常不需要这样做,如果这样做,您可能需要在其上构建一个完整的元数据结构,就像构建的那样
ApiExplorer
在 ASP.NET Core 之上执行此操作。DI 系统不会支持或涉及该结构,因为您正在查询系统,而不是将实时实例注入系统。 - 如果您依赖 DI 来解析控制器,您可能不需要一个完全独立的控制器提供程序。一旦你知道你需要什么类型的请求,你就可以解决它。
这就是说,虽然我会回答这个问题,但这里的设计方式可能是你想看的。您在做什么,试图让 DI 与列出有关应用程序的元数据...似乎有些倒退(您将根据类型列表提供 DI 容器,而不是从 DI 容器中获取类型列表)。
但是,让我们随它去吧。鉴于:
- 有向 Autofac 注册的控制器
- 控制器没有通用的基类或接口
- 您可以查询的控制器上没有属性
我要做的是用一些元数据注册所有控制器。您需要一些东西才能在容器中所有类型的列表中找到控制器。
builder.RegisterType<ControllerX>().WithMetadata("controller", true);
builder.RegisterType<ControllerY>().WithMetadata("controller", true);
现在在插件控制器中,您需要注入一个,ILifetimeScope
因为您必须查询已注册的内容列表。ILifetimeScope
注入控制器的 将与解析插件控制器本身的范围相同。
您可以使用注入的范围来查询组件注册表中标记有元数据的内容。
public class PluginControllerProvider : ICustomControllerProvider
{
private readonly Type[] _controllerTypes;
public PluginController(ILifetimeScope scope)
{
_controllerTypes = scope
.ComponentRegistry
.Registrations
.Where(r => r.Metadata.ContainsKey("controller"))
.Select(r => r.Activator.LimitType)
.ToArray();
}
public IEnumerable<Type> GetControllerTypes()
{
return _controllerTypes;
}
}
现在,免责声明:
- 如果您在子生命周期范围内注册更多控制器(例如,在
BeginLifetimeScope()
调用期间),您将需要该范围内的控制器提供程序,否则它将无法获得所有控制器类型。提供者需要来自具有所有注册的范围。 - 如果您正在使用注册源(如
AnyConcreteTypeNotAlreadyRegisteredSource
),则不会捕获来自注册源的内容。它只会捕获来自ContainerBuilder
.
但它应该工作。
推荐阅读
- kubernetes - 如何在自定义环境中设置 2 节点 Kubernetes 集群
- django - Modelform 未使用当前值填充其字段
- node.js - Firebase 验证 ID 令牌 - Node.js
- database - 如何有效地从 DynamoDB 中检索海量数据?
- ios - 当应用程序通过推送通知从终止状态打开时,iOS Web 视图应用程序崩溃
- angular - 带有 aria-live 的可访问性 Angular5
- r - 2d 绘图为空(第三个变量中的 2 行和线条颜色)
- php - Behat 脚本无法检测到 CKEditor 工具栏元素
- google-cloud-platform - GCP 虚拟机实例 - 操作系统以其他用户身份登录
- html - 如何使这个左侧边栏在移动设备上可见?