我正在使用Autofac作为C#解决方案中的依赖项注入系统,该解决方案跨越多个类库和多个可执行文件。我正在使用模块来配置 Autofac,但这仍然给我留下了构建 DI 容器的问题,这取决于我为哪个可执行文件编写它。
我尝试使用 Autofac 的 RegisterAssemblyModules,但您必须为其提供要扫描的程序集列表,并且在使用类库程序集中的某个 Type 之前,程序集不会加载,因此无法扫描。
有些人建议加载 bin 目录中的每个程序集,该目录可能包含 Autofac 模块定义。但这似乎带来了不受欢迎的组件被付诸行动的风险。
所以我想出的是这个静态类,它是在一个公共类库中定义的:
public static class Container
{
private static IContainer _instance;
private static Dictionary<string, Assembly> _moduleAssemblies = new Dictionary<string, Assembly>();
public static void RegisterAutofacModuleAssembly<T>()
where T : class
{
var assembly = typeof(T).Assembly;
if( !_moduleAssemblies.ContainsKey( assembly.FullName ) )
_moduleAssemblies.Add( assembly.FullName, assembly );
}
public static IContainer Instance
{
get
{
if( _instance == null )
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyModules( _moduleAssemblies.Select( ma => ma.Value ).ToArray() );
_instance = builder.Build();
}
return _instance;
}
}
}
您可以通过在应用程序的启动代码中包含如下行来使用它:
public static void Main(string[] args)
{
AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<ScannerApp>();
AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<AppConfiguration>();
这是一个合理的解决方案吗?如果有更好,更灵活的,我会有兴趣了解它。
IOptions<>
绑定系统中的问题
在实施@Nightowl888的建议时,我遇到了Microsoft配置IOptions<>
系统的问题。以下是我尝试配置 Autofac 以解析应用程序配置对象的方式:
protected override void Load( ContainerBuilder builder )
{
base.Load( builder );
var config = new ConfigurationBuilder()
.AddJsonFile( AppConfiguration.WebJobsConfigFile, false )
.AddUserSecrets<ConfigurationModule>()
.AddEnvironmentVariables()
.Build();
builder.Register<AppConfiguration>( ( c, p ) =>
{
var retVal = new AppConfiguration( c.Resolve<ILogger>() );
config.Bind( retVal );
return retVal;
} )
.SingleInstance();
}
在调用 Bind() 时出现问题。当它遍历和解析配置信息时,它期望通过无参数构造函数创建各种对象......这使得使用构造函数注入变得困难。
如果我无法使用构造函数注入,我需要能够针对构造函数代码中的 DI 容器进行解析。我不明白如何定义一个库程序集,该程序集不会在特定 DI 容器的分辨率语义中进行硬连接。
思潮?除了"放弃IOptions<>
系统",我已经考虑过了,但它提供了许多我想维护的好处。
每个可执行应用程序都应具有自己唯一的 DI 配置。库和框架应构建为对 DI 友好,但实际上不引用任何 DI 容器。
组合根是应用程序的配置。在应用程序之间共享它类似于在应用程序之间共享.config
文件 - 也就是说,通常不会这样做。请参阅组合根重用。
如果要使用 autofac 模块,它们应该是使用它们的应用程序的一部分,而不是包含在与正在组成的组件的程序集中。虽然您不必在每个应用程序中重复配置代码似乎获得了一些东西,但这样做的主要问题是这意味着您的应用程序已经失去了 DI 的主要优势之一 - 也就是说,它无法提供任何给定组件的替代实现。使库松散耦合的全部意义在于,它允许由承载组件的应用程序最终决定如何将应用程序耦合在一起。
宠物烦恼:另请注意,您有多少项目或解决方案与应用程序的运行时行为(例如它的组成方式)完全无关。项目和解决方案是在编译代码之前组织代码的一种方式 - 一旦代码被编译,就没有"项目"或"解决方案"的概念,你剩下的只是可能依赖于其他"程序集"的"程序集"。对于每个应用程序,您最终都会得到一个可执行程序集和 0 个或多个依赖程序集。组合根应仅存在于可执行程序集中。