【问题标题】:3 tier Ninject Console App3 层 Ninject 控制台应用程序
【发布时间】:2015-12-05 04:39:49
【问题描述】:

我有一个现有的 Web 项目,我将其转换为使用 Ninject,并将绑定设置为 InRequestScope。

// binding in AppStart
kernel.Bind<IDbContext>().To<DbContext>().InRequestScope();

...

// business layer
public class BusinessService {
    public BusinessService(IDbContext context) {
        this.Context = context;
    }

    private IDbContext Context { get; set; }

    public void UpdateUser(int userId) {
        User user = this.Context.Users.Single(u => u.UserId == userId);
        user.LastUpdated = DateTime.Now;
        this.Context.SaveChanges();
    }
}

现在,我正在尝试转换一些使用业务层代码的控制台应用程序。

// ... Console App ...
foreach(int userId in usersNeedingToBeUpdated) {
    // do stuff to each user
    BusinessService businessService = kernel.Get<BusinessService>();
    businessLayer.UpdateUser(userId);
}

但是,我无法理解范围。我希望每次我为 Ninject 执行 kernel.Get() 时都给我一个新的 IDbContext 并处理旧的 IDbContext。我试过做

kernel.Bind<IDbContext>().To<DbContext>().InParentScope();

这一直有效,直到有人直接请求 IDbContext:

kernel.Get<IDbContext>();

然后我得到一个空指针异常,因为没有父作用域。如果我改用 TransientScope,则 Ninject 不会处理 IDbContext1。我怎样才能将它带到每个内核的位置。Get() 我得到一个新服务以及新的依赖项和旧的依赖项被释放?

我已阅读this post,但我仍然不确定该怎么做。

【问题讨论】:

  • 请参阅 here 了解 InRequestScope 的工作原理,并希望为您提供足够的详细信息,让您了解自己需要什么。

标签: c# dependency-injection scope ninject


【解决方案1】:

对于您的控制台应用,如果您这样做了

kernel.Get<IDbContext>();

那么您可以使用的唯一(预定义)范围是:

  • .InSingletonScope()
  • .InTransientScope()
  • .InThreadScope()
  • .InCallScope()

为什么?其他依赖于存在的 ninject 上下文。例如,'.InParentScope()" 将查找注入 IDbContext 的对象(通过构造函数 - 或属性注入) - 但没有,因为你做了 kernel.Get&lt;...&gt;。所以它失败了。

大多数可用于kernel.Get&lt;&gt; 的作用域对您没有帮助。 也许如果您的控制台应用程序生命周期与IDbContext IDbContext 在控制台应用程序的多个对象中使用之一紧密耦合,那么使用.InSingletonScope() 可能是有意义的。使用 '.InSingletonScope()' ninject 在第一次请求时实例化对象,并在内核被释放/关闭时释放它。 但是 '.InSingletonScope()' 肯定不适合你的 web 项目。

所以基本上你需要两个不同的绑定:

  • Bind&lt;IDbContext&gt;().To&lt;DbContext&gt;().InRequestScope(); 用于网络应用程序
  • 控制台应用程序的Bind&lt;IDbContext&gt;().To&lt;DbContext&gt;();(默认瞬态范围)

作为一种技巧,如果您不想定义单独的绑定,您也可以这样做

kernel.Get<DbContext>();

在控制台应用程序中。

还有很多其他可能性,但它们在很大程度上取决于您的用例/实现。您可以使用 '.InScope()' 实现自己的范围

另见https://github.com/ninject/ninject/wiki/Object-Scopes

【讨论】:

    【解决方案2】:

    由于看起来您可能在创建 DbContext 实例后对其进行了存储,因此您应该能够完全忽略范围。默认情况下,如果没有定义范围,Ninject 将返回一个新实例,因为 InTransientScope() 是默认值。

    https://github.com/ninject/ninject/wiki/Object-Scopes

    如果需要,您还可以实现自己的机制来返回特定实例。我在上面提供的链接中有这样做的说明。

    希望我正确阅读了您的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-15
      • 2016-04-20
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      相关资源
      最近更新 更多