1

主要问题:如何发现在其他层中使用 Ninject.MVC3 配置的依赖项?

背景:

我在我的一个 ASP.NET MVC4 项目中使用 Ninject.MVC3。

我以前使用过 ServiceLocator,但对 Ninject 来说是新手。通过新的增强功能,设置和配置 Ninject 非常简单。

新的 Ninject.MVC3 Nuget 包,在NinjectWebCommon您的 Web 项目的 App_Start 文件夹中添加一个“”类,这是我们配置所有依赖项的地方。这个类是静态的,除了返回 void 的 Start 和 Stop 静态方法之外不暴露任何东西。

为了使用它,你可以在它的 " RegisterServices" 方法中配置一个依赖,例如

    private static void RegisterServices(IKernel kernel)
    { 
        kernel.Bind<IDataContext>().To<MyDataContext>().WithConstructorArgument("connectionString", "name=MyDataContext");

        kernel.Bind<IRoleService>()
        .To<RoleService>()
        .WithConstructorArgument("dbContext", context => context.Kernel.Get<IDataContext>());
    }

在业务层中,我们可以使用任何已配置的服务,例如

public class RoleService : IRoleService
{
    private readonly IDataContext _dbContext;

    public RoleService(IDataContext dbContext)
    {
        _dbContext = dbContext;
    }
}

现在假设我们要向这个类添加一个新的依赖项,比如 ILogger RoleService。目前我必须这样做是这样的:

public class RoleService : IRoleService
{
    private readonly IDataContext _dbContext;
    private ILogger _logger;

    public RoleService(IDataContext dbContext, ILogger logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }
}

我想知道这是允许模块发现依赖项的唯一(或理想或标准)方法吗?

ServiceLocator会这样做:

    public class RoleService : IRoleService
    {
        private readonly IDataContext _dbContext;
        private readonly Lazy<ILogger> _logger;        

        public RoleService(IDataContext dbContext)
        {
            _dbContext = dbContext;
            _logger = Locator.Current.GetInstanceLazy<ILogger>();
        }
    }

我试着环顾四周,但大多是为 Ninject 找到基于构造函数的注入。

基于构造函数的方法的问题是,显然当您添加更多依赖项时,构造函数参数列表会增长。我知道,SRP 出现了 :) 但你知道 <3 依赖是正常的。每个类都需要 DbContext,每个类都需要一个记录器,如果你碰巧有一个单独的审计功能,那就是第三个。

基于属性的注入是怎么回事。我刚试过,我添加了一个像这样的属性:

    [Inject]
    public IRoleWrapper RoleWrapper { get; set; }

在业务层中存在的 RoleService 类中。该属性未初始化并设置为 null。我应该怎么做才能让 Ninject 初始化它,请注意 ninject 初始化是在 MVC Web 项目中完成的。

总结一下我的问题是:

  1. 这两个构造函数与属性注入 wrt Ninject MVC3 包有什么更好的方法?

  2. 有没有另一种方法可以像使用 ServiceLocator 一样发现业务层类中的依赖关系?

  3. 在上述情况下,属性注入应该如何工作?

提前致谢。

4

1 回答 1

2

1)我更喜欢构造函数,因为它给了我更好的概述,我已经习惯了
2)你应该在层的底部创建 StandardKernel 对象,包括 UI 项目在内的每个组件都应该使用该对象
3)你必须通过 ninject 实例化. Ninject 将填充构造函数参数,并搜索属性注入的类型。
例子:

  public interface IBusinessClass {
    int DoWork();
  }

  public class BusinessClass : IBusinessClass
  {
    public int DoWork()
    {
      return 10;
    }
  }
  public interface IBusinessClass2
  {
    int DoWork2();
  }

  public class BusinessClass2 : IBusinessClass2
  {
    public int DoWork2()
    {
      return 20;
    }
  }
  public class Consumer
  {
    public IBusinessClass2 BusinessClass2 { get; set; }

    [Inject]
    public IBusinessClass BusinessClass { get; set; }

    public Consumer(IBusinessClass2 businessClass2)
    {
      BusinessClass2 = businessClass2;
    }
  }
  class Program
  {
    static void Main(string[] args)
    {
      IKernel kernel = new StandardKernel();
      kernel.Bind<IBusinessClass>()
            .To<BusinessClass>();
      kernel.Bind<IBusinessClass2>()
            .To<BusinessClass2>();

      Consumer c = kernel.Get<Consumer>();
      Console.WriteLine(c.BusinessClass.DoWork());
      Console.WriteLine(c.BusinessClass2.DoWork2());
      Console.ReadKey();
    }
  }

更新:
关于 MVC 模块。添加到您的项目时,它会为您生成 NinjectWebCommon.cs。
Create()里面有一个方法:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    RegisterServices(kernel);
    return kernel;
}

修改此方法 n 以使用新内核,但您的内核来自基础库:

private static IKernel CreateKernel()
{
    var kernel = // kernel from base library
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    RegisterServices(kernel);
    return kernel;
}
于 2013-08-30T11:54:06.457 回答