其他层中的依赖项发现';s模块使用Ninject.MVC3

本文关键字:模块 MVC3 Ninject 依赖 发现 其他 | 更新日期: 2023-09-27 18:29:34

主要问题:如何在其他层中发现使用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;
    }
}

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

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. 从这两个Constructor Vs Property注入w.r.t.Ninject MVC3包中,有什么更好的方法?

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

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

提前谢谢。

其他层中的依赖项发现';s模块使用Ninject.MVC3

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;
}