我正在努力解决如何在模块中组织我的Autofac组件注册,因为某些模块本身具有依赖性。
我在接口中实现了配置数据的抽象(即 web.config):
interface IConfigurationProvider
{
T GetSection<T>(string sectionName)
where T : System.Configuration.ConfigurationSection;
}
以及ASP.NET(WebConfigurationProvider
)和“桌面”应用程序(ExeConfigurationProvider
)的实现。
然后我的一些autofac模块需要IConfigurationProvider
作为构造函数参数,但有些则不需要:
class DependentModule : Module
{
public DependentModule(IConfigurationProvider config)
{
_config = config;
}
protected override void Load(ContainerBuilder builder)
{
var configSection = _config.GetSection<CustomConfigSection>("customSection");
builder.RegisterType(configSection.TypeFromConfig);
}
private readonly IConfigurationProvider _config;
}
class IndependentModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(/* other stuff not based on configuration */);
}
}
由于RegisterType()
扩展方法不接受注册委托(Func<IComponentContext, T>
),就像Register()
那样,我无法预先注册IConfigurationProvider
然后在我注册配置中指定的类型时解决它,例如:
// this would be nice...
builder.RegisterType(c => c.Resolve<IConfigurationProvider>().GetSection<CustomConfigSection>("sectionName").TypeFromConfig);
这意味着我需要能够在<{1}}上注册模块,包括>>依赖。
很明显如何手动实例化每个模块并注册它:
IConfigurationProvider
但是我不想手动实例化我的模块 - 我想扫描模块的程序集并自动注册它们(如in this question所述)。所以我必须使用反射来扫描程序集中的IConfigurationProvider configProvider = ...;
var builder = new ContainerBuilder();
builder.RegisterModule(new DependentModule(configProvider));
builder.RegisterModule(new IndependentModule());
using (var container = builder.Build())
{
...
}
类型,并使用IModule
来创建可注册的实例。但是,我如何知道是否将Activator.CreateInstance
作为构造函数参数传递。当其他模块具有其他或不同的依赖项时会发生什么?
必须有一种更简单的方法来完成基本任务:注册通过接口提供的某些配置中指定的类型,对吧?那我该怎么做呢?
答案 0 :(得分:7)
你可以这样做:
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;
using NUnit.Framework;
namespace Yo_dawg
{
[TestFixture]
public class I_heard_you_like_containers
{
[Test]
public void So_we_built_a_container_to_build_your_container()
{
var modules = GetModules();
Assert.That(modules.Length, Is.EqualTo(4));
var builder = new ContainerBuilder();
foreach (var module in modules)
builder.RegisterModule(module);
var container = builder.Build();
}
private IModule[] GetModules()
{
var builder = new ContainerBuilder();
var configurationProvider = new ConfigurationProvider();
builder.RegisterInstance(configurationProvider).AsImplementedInterfaces().ExternallyOwned();
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.IsAssignableTo<IModule>())
.AsImplementedInterfaces();
using (var container = builder.Build())
return container.Resolve<IEnumerable<IModule>>().ToArray();
}
}
public class ModuleA : Module
{
public ModuleA(IConfigurationProvider config)
{
}
}
public class ModuleB : Module
{
public ModuleB(IConfigurationProvider config)
{
}
}
public class ModuleC : Module
{
}
public class ModuleD : Module
{
}
public interface IConfigurationProvider
{
}
public class ConfigurationProvider : IConfigurationProvider
{
}
}
答案 1 :(得分:2)
对于这种情况,Autofac自己的XML配置似乎涵盖了您所定位的方案。添加新的IConfigurationProvider
机制似乎重新发明了容器已经提供的此功能。基础知识记录在:https://code.google.com/p/autofac/wiki/XmlConfiguration。配置语法具有对模块的内置支持。
Paul Stovell有一个很好的选择,允许模块在代码中注册,但从config接收参数 - 请参阅:http://www.paulstovell.com/convention-configuration。希望这有帮助!