2

我有 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;
        });
    }
}

我希望有更好的方法来做到这一点。

更新2:

解决这个不足的另一种方法是基于 MySettings 类创建 2 个新的设置类。这样每个实例唯一地对应一个类,Autofac 可以很容易地解析它。我不想仅仅为了让 Autofac 工作而做。

4

2 回答 2

9

最简单的解决方案是使用 Autofac 的Named注册功能

因此,使用名称注册您的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”提供程序。您可以将此提供程序作为具体类,也可以使用 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您可以识别哪个控制器应该获取哪些设置,例如字符串、枚举等。

于 2013-09-22T17:32:02.417 回答
0

另一种选择是使用AutoFac 的元数据功能

public UserController(IEnumerable<Meta<ISettings>> allSettings)
{
    this.settings = allSettings.Where(s => ....);
}

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

于 2013-09-22T19:20:23.957 回答