我正在做的事情正在发挥作用,但我认为它可能会做得更好(因此,可维护性更强)。
我正在使用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有一些我误解的原因。
答案 0 :(得分:1)
编辑:
.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.Current - 当时为null - 并抛出异常。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
的每个依赖关系都将收到相同的网络研讨会上下文实例。此外,如果同一请求中的其他人想要注入网络研讨会上下文,他也会获得相同的实例。