使用参数Ninject WebAPI依赖项

时间:2016-04-14 15:06:17

标签: c# asp.net-web-api ninject

我正在尝试使用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 需要一个参数来声明它是否存在。 有谁知道如何让这段代码起作用?

1 个答案:

答案 0 :(得分:1)

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

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

您的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。基类是设计问题的标志。所以抛弃基类并将IModelFactoryIServiceInterface注入需要使用它们的具体类的构造函数中:

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。这包括抛出异常等内容。防止从构造函数中抛出异常,因为这会产生resolving your object graph unreliable

不要使用Service Locator anti-pattern,请确保组件只有one constructor,不要注入任何runtime data into them并注意constructor over-injection,因为这表示违反了Single Responsibility Principle