我在跨多个类库和多个可执行文件的 C# 解决方案中使用 Autofac 作为依赖注入系统。我正在使用模块来配置 Autofac,但这仍然给我留下了构建 DI 容器的问题,这取决于我为哪个可执行文件编写它。
我尝试使用 Autofac 的 RegisterAssemblyModules,但您必须为其提供要扫描的程序集列表,并且在使用类库程序集中的某些类型之前,不会加载程序集,因此无法扫描。
有些人建议加载 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 以解析 AppConfiguration 对象的方式:
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<>
系统”之外,它还提供了许多我想保持的好处。