Ninject 带有参数的 WebAPI 依赖项

Ninject WebAPI dependency with a parameter

我第一次尝试使用 this little library 设置 Ninject。 我有一个基本控制器,目前看起来像这样:

public class BaseController : ApiController
{

    // Private properties
    private IModelFactory factory;

    // Public properties
    public IServiceInterface Connection { get; private set; }
    public IModelFactory Factory { get { return this.factory ?? (this.factory = new ModelFactory()); } }

    /// <summary>
    /// Default constructor
    /// </summary>
    public BaseController()
    {

        // Get our database settings
        var setting = ConfigurationManager.AppSettings["Server"].ToUpper();
        var type = (setting == "LIVE") ? ServiceInterface.ServerType.Azurerelay_live : ServiceInterface.ServerType.Azurerelay_test;

        try
        {

            // Apply to our public properties
            this.Connection = new ServiceInterface(type);

        } catch
        {

            // Throw a 401 error
            throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
        }
    }
}

我想在此构造函数上使用 Ninject,但我似乎无法弄清楚如何执行 ServiceInterface,因为它需要一个参数。 我尝试像这样绑定服务:

// List and Describe Necessary HttpModules
// This class is optional if you already Have NinjectMvc
public class NinjectHttpModules
{
    //Return Lists of Modules in the Application
    public static NinjectModule[] Modules
    {
        get
        {
            return new[] { new MainModule() };
        }
    }

    //Main Module For Application
    public class MainModule : NinjectModule
    {
        public override void Load()
        {
            //TODO: Bind to Concrete Types Here
            Kernel.Bind<IServiceInterface>().To<ServiceInterface>();
            Kernel.Bind<IFactory>().To<Factory>();
        }
    }
}

并将我的构造函数更改为:

public class BaseController : ApiController
{

    // Public properties
    public readonly IServiceInterface Connection;
    public readonly IModelFactory Factory;

    /// <summary>
    /// Default constructor
    /// </summary>
    public BaseController(IServiceInterface connection, IModelFactory factory)
    {

        try
        {

            // Apply to our public properties
            this.Connection = connection;
            this.Factory = factory;

        } catch
        {

            // Throw a 401 error
            throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
        }
    }
}

但这行不通,因为 ServiceInterface 需要一个参数来说明它是否处于活动状态。 有谁知道我怎样才能让这段代码工作?

防止在运行时从 AppSettings 等位置读取配置值。不仅不需要多次阅读它们(性能),而且在整个应用程序中分散使用它们对可维护性和可靠性具有深远的影响。相反,将配置值的检索移动到应用程序的启动路径。这个:

  • 避免不得不一遍又一遍地读取它们,允许应用程序在缺少值时快速失败。
  • 提高了可测试性,因为 class松散了对配置系统的依赖。
  • 在一个位置保持对这些配置值的访问,从而更容易更改应用程序或配置文件的结构。

您的 Composition Root 应如下所示:

public override void Load()
{
    var setting = ConfigurationManager.AppSettings["Server"].ToUpper();
    var type = (setting == "LIVE")
        ? ServiceInterface.ServerType.Azurerelay_live
        : ServiceInterface.ServerType.Azurerelay_test;

    Kernel.Bind<IServiceInterface>().ToMethod(c => new ServiceInterface(type));
    Kernel.Bind<IModelFactory>().ToMethod(c => new ModelFactory());
}

另一件事是你应该赞成composition over inheritance。 Base classes 是设计问题的标志。因此,放弃基础 class 并将 IModelFactoryIServiceInterface 注入需要使用它们的具体 classes 的构造函数中:

public class HomeController : ApiController
{
    private readonly IModelFactory modelFactory;
    private readonly IServiceInterface serviceInterface;

    public HomeController(IModelFactory modelFactory, IServiceInterface serviceInterface) 
    {
        this.modelFactory = modelFactory;
        this.serviceInterface = serviceInterface;
    }

    // actions here
}

此外,除了存储传入的依赖项之外,还要防止在构造函数中执行任何操作。你injection constructors should be simple. This includes things like throwing exceptions. Prevent throwing exceptions from constructors, because this makes resolving your object graph unreliable.

避免使用 Service Locator anti-pattern, make sure components only have one constructor, don't inject any runtime data into them and look out for constructor over-injection, since this is an indication of violating the Single Responsibility Principle