3层Ninject控制台应用程序

时间:2013-12-10 19:51:47

标签: c# dependency-injection scope ninject

我有一个现有的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不会丢弃IDbContext 1 。我怎样才能把它带到每个kernel.Get&lt;&gt;()的位置我得到一个新的服务以及新的依赖项和旧的依赖项被处理?

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

2 个答案:

答案 0 :(得分:1)

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

kernel.Get<IDbContext>();

然后,您可以使用的唯一(预定义)范围是:

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

为什么呢?其他人依赖于那里的ninject环境。例如,“。InParentScope()”将查找注入IDbContext的对象(通过构造函数 - 或属性注入) - 但是没有,因为你执行了kernel.Get<...>。所以它失败了。 / p>

大多数kernel.Get<>可用的范围对您无济于事。 也许如果您的控制台应用程序生命周期紧密耦合到控制台应用程序中的多个对象中使用的IDbContext IDbContext,那么使用{可能是有意义的{1}}。使用'.InSingletonScope()'ninject在第一个请求时实例化对象,并在内核处理/关闭时处理它。 但是'。InSingletonScope()'肯定不适合你的网络项目。

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

  • .InSingletonScope()用于Web应用程序
  • 控制台应用程序的
  • Bind<IDbContext>().To<DbContext>().InRequestScope();(默认瞬态范围)

作为一个黑客,如果你不想定义单独的绑定,你也可以只做

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

在控制台应用程序中。

还有很多其他可能性,但它们高度依赖于您的用例/实现。您可以使用'.InScope()'

实现自己的范围

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

答案 1 :(得分:0)

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

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

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

希望我能正确阅读你的问题。