Ninject caching an injected DataContext? Lifecycle Management?
我有一系列非常奇怪的错误被扔进了我的仓库。未找到或更改行,2个更新中的1个失败…没有任何意义。
就好像我的DataContext实例正在缓存中…没什么道理,我正在考虑换个职业。
然后我注意到DataContext实例是使用依赖项注入和Ninject传入的(这是我第一次使用DI…)。我抽出依赖注射,一切恢复正常。立刻。
所以依赖注入是个问题,但我仍然不知道为什么。我推测Ninject正在缓存注入的数据上下文。
这是正确的吗?
编辑:ninject绑定如下:
1 2 | Bind<IPupilBlockService>().To<SqlPupilBlockService>() .WithConstructorArgument("db", new dbDataContext()); |
对于生存期必须显式管理的任何对象(例如实现
1 2 3 4 | public interface IDbDataContextFactory { dbDataContext CreateNew(); } |
使用方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class SqlPupilBlockService { private IDbDataContextFactory contextFactory; public SqlPupilBlockService( IDbDataContextFactory contextFactory) { this.contextFactory = contextFactory; } public void DoSomeOperation() { using (var db = this.contextFactory.CreateNew()) { // use the dbDataContext here. } } } |
的实现非常简单,如下所示:
1 2 3 4 5 6 7 | public class DbDataContextFactory : IDbDataContextFactory { public dbDataContext CreateNew() { return new dbDataContext(); } } |
注册过程如下:
1 | Bind<IDbDataContextFactory>().To<DbDataContextFactory>(); |
工厂的使用使得它非常明确谁是被创建对象的所有者,谁应该控制它的生命周期。这使您的代码更易于阅读,并遵循最不令人惊讶的原则。
更新
我提交这个答案已经一年多了。现在,我不再使用工厂,而是经常注入数据上下文本身,并根据每个(Web)请求对其进行注册。但是,可能需要改变您设计应用程序的方式,就像往常一样:这取决于情况。请看一下这个答案。
@Steven给出了一个很好的解释,但实际上,Ninject已经为您提供了一种方法来指定为每个请求生成一个实例:inRequestScope。
1 2 3 4 | Bind<IPupilBlockService>() .To<SqlPupilBlockService>() .InRequestScope() .WithConstructorArgument("db", new dbDataContext()); |
看看激活行为。可能您的DataContext被绑定在单个作用域中,或者其他作用域中的某个作用域将导致从内核返回同一实例,具体取决于您的调用上下文。
(我对ninject不太熟悉,但是默认情况下是瞬态范围,我希望在应用程序代码中的某个地方,DataContext被明确定义为具有非瞬态范围)