如何让Autofac将同一类的不同唯一初始化实例注入不同的控制器?

时间:2013-09-20 18:21:20

标签: autofac

我有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工作。

2 个答案:

答案 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 => ....);
}

这将允许您获取多个设置对象,并根据每个设置对象提供的元数据选择所需的对象。