我有2个控制器,都需要一个代表一组设置的MySettings
类型的对象。每个控制器都需要其自定义设置集。为了在模块注册时执行此操作,我手动创建了2个设置对象并将它们都放入容器中。问题是如何指定每个控制器应该注入自己的预定义的MySettings类型的自定义初始化实例?
更新:
现在有一个丑陋的解决方法,基本上使Autofac无用,因为所有解析都是手工完成的:
public class MyModule : Module {
protected override void Load(ContainerBuilder builder) {
builder.Register(context => {
var productControllerSettings = new MyListSettings(
pageSize: 20,
orderBy: "Name",
orderDirection: OrderDirection.Ascending
);
// and hell of other parameters that I need to resove
// by hands by doing context.Resolve<...> for each of them
var productController = new ProductController(
productControllerSettings
/*, the reset of parameters */
);
return productController;
});
builder.Register(context => {
var userControllerSettings = new MyListSettings {
pageSize: 20,
orderBy: "LastName",
orderDirection: OrderDirection.Ascending
};
var userController = new UserController(
userControllerSettings
/*, the rest of parameters resolved by calling context.Resolve<> by hands */
);
return userController;
});
}
}
我希望必须有更好的方法。
UPDATE2:
解决这一不足的另一种方法是根据MySettings类创建2个新类设置。这样每个实例唯一对应一个类,Autofac可以轻松解决它。我不想只是为了让Autofac工作。
答案 0 :(得分:8)
最简单的解决方案是使用Autofac的Named
registration feature。
因此,请使用名称注册MyControllerSettings
个实例,并在注册控制器时将此名称用作参数:
var productControllerSettings = new MyListSettings(
pageSize: 20,
orderBy: "Name",
orderDirection: OrderDirection.Ascending);
builder.RegisterInstance(productControllerSettings)
.Named<MyListSettings>("productControllerSettings");
var userControllerSettings = new MyListSettings(
pageSize: 20,
orderBy: "LastName",
orderDirection: OrderDirection.Ascending);
builder.RegisterInstance(userControllerSettings)
.Named<MyListSettings>("userControllerSettings");
builder.RegisterType<ProductController>()
.WithParameter(
ResolvedParameter.ForNamed<MyListSettings>("productControllerSettings"));
builder.RegisterType<UserController>()
.WithParameter(
ResolvedParameter.ForNamed<MyListSettings>("userControllerSettings"));
但是,此解决方案需要在注册期间列出所有控制器命名的参数对,这可能容易出错。
另一种方法是,您不直接依赖控制器中的MyListSettings
,而是依赖于“MyListSettings”提供程序。您可以将此提供程序作为具体类,或者可以使用relation types内置的Autofac来创建轻量级提供程序,如IIndex
。
所以你的控制器看起来像这样:
public class ProductController
{
private readonly MyListSettings productControllerSettings;
public ProductController(Func<Type, MyListSettings> settingsProvider)
{
this.productControllerSettings = settingsProvider(GetType());
}
}
public class UserController
{
private readonly MyListSettings userControllerSettings;
public UserController(Func<Type, MyListSettings> settingsProvider)
{
this.userControllerSettings = settingsProvider(GetType());
}
}
并相应注册:
var productControllerSettings = new MyListSettings(
pageSize: 25,
orderBy: "Name",
orderDirection: OrderDirection.Ascending);
builder.RegisterInstance(productControllerSettings)
.Keyed<MyListSettings>(typeof (UserController1));
var userControllerSettings = new MyListSettings(
pageSize: 20,
orderBy: "LastName",
orderDirection: OrderDirection.Ascending);
builder.RegisterInstance(userControllerSettings)
.Keyed<MyListSettings>(typeof (ProductController1));
//register the provider func
builder.Register<Func<Type, MyListSettings>>(
c => (t) => c.Resolve<IIndex<Type, MyListSettings>>()[t]);
builder.RegisterType<ProductController>();
builder.RegisterType<UserController>();
您应该注意,您可以使用Keyed
的任何内容,而不仅仅是Type
任何可以识别哪个控制器应该获取字符串,枚举等设置的任何内容。
答案 1 :(得分:0)
另一种选择是使用AutoFac's Metadata features。
public UserController(IEnumerable<Meta<ISettings>> allSettings)
{
this.settings = allSettings.Where(s => ....);
}
这将允许您获取多个设置对象,并根据每个设置对象提供的元数据选择所需的对象。