Ninject将常见的DbContext注入许多存储库

时间:2014-06-04 02:54:57

标签: ninject ninject.web.mvc

我正在做的事情正在发挥作用,但我认为它可能会做得更好(因此,可维护性更强)。

我正在使用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有一些我误解的原因。

1 个答案:

答案 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();

你遇到了一个重大问题。有两种情况可以解决这个问题:

  1. 您正在尝试在请求之外创建A。它会失败。实例化DbContext,ninject将查找HttpContext.Current - 当时为null - 并抛出异常。
  2. 您正在尝试在请求期间创建A。实例化将成功。但是,当您尝试在请求后或新请求期间使用A(依次访问DbContext)的某些功能时,它会抛出ObjectDisposedException
  3. 总结一下,当您访问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的每个依赖关系都将收到相同的网络研讨会上下文实例。此外,如果同一请求中的其他人想要注入网络研讨会上下文,他也会获得相同的实例。