Ninject将公共DbContext注入到多个存储库中
-
21-12-2019 - |
题
我正在做一些工作,但我认为它可能会做得更好(因此,具有更多的可维护性)。
我正在使用Ninject将各种东西注入到控制器中。我需要解决的问题是每个存储库的DbContext需要相同。即内存中的同一个对象。
虽然,下面的代码确实实现了这一点,我的Ninject 通用配置文件 已经开始变得相当混乱,因为我必须为每个控制器编写类似的代码:
kernel.Bind<OrderController>().ToMethod(ctx =>
{
var sharedContext = ctx.Kernel.Get<TTSWebinarsContext>();
var userAccountService = kernel.Get<UserAccountService>();
ILogger logger = new Log4NetLogger(typeof(Nml.OrderController));
ILogger loggerForOrderManagementService = new Log4NetLogger(typeof(OrderManagementService));
var orderManagementService = new OrderManagementService(
new AffiliateRepository(sharedContext),
new RegTypeRepository(sharedContext),
new OrderRepository(sharedContext),
new RefDataRepository(),
new WebUserRepository(sharedContext),
new WebinarRepository(sharedContext),
loggerForOrderManagementService,
ttsConfig
);
var membershipService = new MembershipService(
new InstitutionRepository(sharedContext),
new RefDataRepository(),
new SamAuthenticationService(userAccountService),
userAccountService,
new WebUserRepository(sharedContext)
);
return new OrderController(membershipService, orderManagementService, kernel.Get<IStateService>(), logger);
}).InRequestScope();
有没有更整洁的方法来做到这一点?
编辑
尝试了以下代码。一旦我发出第二个请求,就会出现一个异常,即DbContext已经被释放。
kernel.Bind<TTSWebinarsContext>().ToSelf().InRequestScope();
string baseUrl = HttpRuntime.AppDomainAppPath;
kernel.Bind<IStateService>().To<StateService>().InRequestScope();
kernel.Bind<IRefDataRepository>().To<RefDataRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
var config = MembershipRebootConfig.Create(baseUrl, kernel.Get<IStateService>(), kernel.Get<IRefDataRepository>());
var ttsConfig = TtsConfig.Create(baseUrl);
kernel.Bind<MembershipRebootConfiguration>().ToConstant(config);
kernel.Bind<TtsConfiguration>().ToConstant(ttsConfig);
kernel.Bind<IAffiliateRepository>().To<AffiliateRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IWebinarRepository>().To<WebinarRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IWebUserRepository>().To<WebUserRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IOrderRepository>().To<OrderRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IInstitutionRepository>().To<InstitutionRepository>().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IRegTypeRepository>().To<RegTypeRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<UserAccountService>().ToMethod(ctx =>
{
var userAccountService = new UserAccountService(config, ctx.Kernel.Get<IUserAccountRepository>());
return userAccountService;
});
kernel.Bind<IOrderManagementService>().To<OrderManagementService>().InRequestScope();
//RegisterControllers(kernel, ttsConfig);
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>().InRequestScope();
kernel.Bind<IMembershipService>().To<MembershipService>().InRequestScope();
我误解了InRequestScope。
解决方案
编辑:.InRequestScope()
将确保所有被注入的东西 那个 绑定将在注入(创建)期间接收完全相同的实例 HttpContext.Current
是一样的。这意味着当客户端发出请求并且内核被要求为实例提供 .InRequestScope()
, ,它将为完全相同的请求返回相同的实例。现在,当客户端发出另一个请求时,将创建另一个唯一实例。当请求结束时,ninject将处理实例,以防它实现 IDisposable
.
然而 考虑以下场景:
public class A
{
private readonly DbContext dbContext;
public A(DbContext dbContext)
{
this.dbContext = dbContext;
}
}
和装订:
IBindingRoot.Bind<DbContext>().ToSelf().InRequestScope();
IBindingRoot.Bind<A>().ToSelf().InSingletonScope();
你给自己带来了一个大问题。有两种情况可以解决这个问题:
- 您正在尝试创建一个
A
请求之外。它会失败。实例化DbContext
, ,ninject会寻找HttpContext。当前-这是空的时间-并抛出异常。 - 您正在尝试创建一个
A
在请求期间。实例化将成功。但是,当您尝试使用A
(正在访问DbContext
反过来)在请求之后或在新请求期间,它会抛出一个ObjectDisposedException
总结一下,一个 ObjectDisposedException
当您访问 DbContext
可以 只有 由两种情况引起:-你正在处理 DbContext
(或一些组件,反过来处置 DbContext
)在请求结束之前。-你正在参考 DbContext
(再次,或指向某些组件,该组件又引用 DbContext
)跨越请求边界。
就这样。没有什么复杂的,但你的对象图。
所以什么会帮助绘制一个对象图。从根/请求根开始。然后当你完成后,从 DbContext
看看是谁打来的 Dispose()
在上面。如果您的代码中没有使用,则必须是Ninject在请求结束时进行清理。这意味着,您需要检查所有对 DbContext
.有人在请求之间保留引用。
原答案:你应该看看范围: https://github.com/ninject/ninject/wiki/Object-Scopes
具体来说, .InRequestScope()
-或者在不适用于您的问题的情况下 - .InCallScope()
你应该很感兴趣。
正如你已经在使用 .InRequestScope()
对于原始绑定,我建议绑定共享上下文类型也 .InRequestScope()
应该是足够的。这意味着每一个依赖 OrderController
将接收相同的网络研讨会上下文实例。此外,如果同一请求中的其他人想要注入网络研讨会上下文,他也将获得相同的实例。
你应该看看范围: https://github.com/ninject/ninject/wiki/Object-Scopes
具体来说, .InRequestScope()
-或者在不适用于您的问题的情况下 - .InCallScope()
你应该很感兴趣。
正如你已经在使用 .InRequestScope()
对于原始绑定,我建议绑定共享上下文类型也 .InRequestScope()
应该是足够的。这意味着每一个依赖 OrderController
将接收相同的网络研讨会上下文实例。此外,如果同一请求中的其他人想要注入网络研讨会上下文,他也将获得相同的实例。