使用 AutoFac 将原始值传递给 ApiController 的简单方法

Easy way to pass primitive value to ApiController using AutoFac

给出如下配置Autofac的方法:

public class DefaultConfigurationModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterApiControllers(System.Reflection.Assembly.GetExecutingAssembly());
    }
}

并给出以下 Web-Api 控制器:

public class MyController : ApiController
{
    private readonly int _someValue;

    public MyController(int someValue)
    {
        _someValue = someValue;
    }
}

someValue 传递给 MyController 的构造函数的最简单方法是什么?

我可以创建一个 MyControllerConfig class 并使用 AutoFac 注册它:

public interface IMyControllerConfig
{
    int SomeValue { get; }
}

public class MyControllerConfig : IMyControllerConfig
{
    public int SomeValue { get; set; }

    public MyControllerConfig(int someValue)
    {
        SomeValue = someValue;
    }
}

并将其添加到我的配置模块中:

builder.Register(c => new MyControllerConfig(123)).As<IMyControllerConfig>();

并更改 MyApiController 以接受 IMyControllerConfig 而不是 int:

public class MyController : ApiController
{
    private readonly int _someValue;

    public MyController(IMyControllerConfig myControllerConfig)
    {
        _someValue = myControllerConfig.SomeValue;
    }
}

IMyControllerConfig 界面可能有点矫枉过正;我本来可以不用的,只是使用了 MyControllerConfig。但是无论哪种方式;将单个(原始)值传递到我的 Api 控制器中,整个 MyControllerConfig class 似乎有些矫枉过正。 肯定有更简单、更干净、更简洁的方法吗?

如果这不是一个 Api控制器,我会这样做:

builder.Register(c => new MyClass(123)).As<IMyInterface>();

...然后将整数传入。但是因为它是一个 WebApi 控制器,我想/喜欢使用 RegisterApiControllers 方法(因为有很多控制器可以be / are registered with this method just fine)我似乎把自己逼到了一个角落。并更改 MyController,使其不会通过 RegisterApiControllers 方法获得“picked up”(例如,通过将其名称更改为不以 'Controller' 结尾)并注册此控制器'manually' 感觉 有点'dirty'。

另一种方法是实现依赖项解析器并在那里施展魔法,但同样,将单个原语传递给构造函数似乎需要大量工作。我理解并同意,使用上述方法(使用 MyControllerConfig class)更适合未来的增强和传递更多的值而不会太麻烦,但我不需要这个特定项目.项目中的所有其他 API 控制器使用无参数构造函数或具有参数接口的构造函数。

注意上面例子中的123"const"实际上来自一个配置文件,只是为了简洁起见;如果它是一个常量,我就不需要构造函数参数,可以直接将它放在 MyController class 中。

鉴于该值是原始值并且它来自配置,因此推荐的解决方案实际上是使用提供程序类型的接口。使用原始构造函数参数(string、int 等)存在很多问题,其中一个主要问题是它们太原始了,你无法 [从类型的角度] 区分每个参数的实际用途是。在容器中为一个需要连接字符串的 class 注册一个字符串,其他一些 class 可能会出于一些不相关的目的无意中获取它。

您描述的例子are actually right out of our FAQ on this topic。如果您t/won不能使用 lambda,而 lambda 正是您正在寻找的 easier/neater/cleaner 方式,那么提供程序接口是下一个最佳选择。

请注意,如果您想使用 lambda,则无需更改控制器。

// Register everything nicely
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Override just the one controller
builder.Register(ctx => new MyController(123)).As<MyController>();

最后获胜,所以当 Web API 尝试解析 MyController 时,它将从 lambda 获得注册。