寻找一个像InRequestScope一样的Ninject范围

在我的服务层上,我在构造函数中注入了一个UnitOfWork和2个存储库。 工作单元和存储库有一个DbContext实例,我想在它们之间共享。 我怎样才能和Ninject做到这一点? 应考虑哪个范围?

不在一个Web应用程序,所以我不能使用InRequestScope

我尝试做类似的事情……而我正在使用DI,但是,我需要我的UoW来Dispose d并创build它。

 using (IUnitOfWork uow = new UnitOfWorkFactory.Create()) { _testARepository.Insert(a); _testBRepository.Insert(b); uow.SaveChanges(); } 

编辑:我只是想确定我明白…后看看https://github.com/ninject/ninject.extensions.namedscope/wiki/InNamedScope我虽然关于我当前的控制台应用程序架构,实际上使用Ninject。

让我们说:

A类是一个服务层类

B类是一个工作单元,它将一个接口(IContextFactory)

C类是一个存储库,它将一个接口(IContextFactory)

这里的想法是能够在2个或更多的资源库上进行上下文操作,并使用工作单元来应用这些变化。

D类是一个上下文工厂(Entity Framework),它提供了一个在B类和C类之间共享的上下文的实例(保存在容器中),也可以用于其他的存储库。

上下文工厂保存在他的容器中的实例,所以我不想重复使用这个实例所有的名字,因为上下文需要被放置在服务operaiton的末尾..这实际上是InNamedScope的主要目的?

解决的办法是,但我不确定我是否做得对,服务实例会变成这样,这意味着他们实际上从来没有处置? :

 Bind<IScsContextFactory>() .To<ScsContextFactory>() .InNamedScope("ServiceScope") .WithConstructorArgument( "connectionString", ConfigurationUtility.GetConnectionString()); Bind<IUnitOfWork>().To<ScsUnitOfWork>(); Bind<IAccountRepository>().To<AccountRepository>(); Bind<IBlockedIpRepository>().To<BlockedIpRepository>(); Bind<IAccountService>().To<AccountService>().DefinesNamedScope("ServiceScope"); Bind<IBlockedIpService>().To<BlockedIpService>().DefinesNamedScope("ServiceScope"); 

更新:这种方法针对NuGet当前工作,但依赖InCallscope实现中的一个exception,已经在当前的Unstable NuGet包中修复。 我会在几天内调整这个答案,以反映最好的方法,经过一番思考。 注意构造东西的高级方法将保持几乎相同,只是Bind<DbContext>()范围的确切细节将起作用。 (提示:在不稳定的CreateNamedScope将工作,或者可以设置命令处理程序作为DefinesNamedScope原因我不只是这样做,我想有一些组成/使用InRequestScope


我强烈build议阅读Ninject.Extensions.NamedScope集成testing(认真地find它们并阅读并重新读取它们)

DbContext 工作单元,所以不需要进一步的包装。

由于您希望能够在飞行中拥有多个“请求”,并希望在他们之间共享单个工作单元,因此您需要:

 Bind<DbContext>() .ToMethod( ctx => new DbContext( connectionStringName: ConfigurationUtility.GetConnectionString() )) .InCallScope(); 

InCallScope()意味着:

  1. 对于为单个kernel.Get() 调用 (因此在调用范围内)组成的给定对象图,每个需要DbContext都将获得相同的实例。
  2. IDisposable 。 当一个Kernel.Release()发生在根对象(或一个Kernel.Components.Get<ICache>().Clear()Dispose()将会被调用,如果不是.InCallScope()

应该没有理由使用InNamedScope()DefinesNamedScope() ; 你没有长寿命的对象,你想从默认的池/父母/分组中排除。

如果你这样做,你应该能够:

 var command = kernel.Get<ICommand>(); try { command.Execute(); } finally { kernel.Components.Get<ICache>().Clear( command ); // Dispose of DbContext happens here } 

命令实现如下所示:

 class Command : ICommand { readonly IAccountRepository _ar; readonly IBlockedIpRepository _br; readonly DbContext _ctx; public Command(IAccountRepository ar, IBlockedIpRepository br, DbContext ctx){ _ar = ar; _br = br; _ctx = ctx; } void ICommand.Execute(){ _ar.Insert(a); _br.Insert(b); _ctx.saveChanges(); } } 

请注意,一般来说,我避免以这种方式有一个隐含的工作单元,而是表示它的创build和Disposal 。 这使命令看起来像这样:

 class Command : ICommand { readonly IAccountService _as; readonly IBlockedIpService _bs; readonly Func<DbContext> _createContext; public Command(IAccountService @as, IBlockedIpServices bs, Func<DbContext> createContext){ _as = @as; _bs = bs; _createContext = createContext; } void ICommand.Execute(){ using(var ctx = _createContext()) { _ar.InsertA(ctx); _br.InsertB(ctx); ctx.saveChanges(); } } 

这不涉及在Bind<DbContext>() (但是需要存在Ninject.Extensions.Factory来从简单的Bind<DbContext>()综合Func<DbContext>

正如在另一个答案中所讨论的 , InCallScope不是解决这个问题的好方法。

现在我正在倾销一些代码,对Ninject.Web.Common的最新NuGet Unstable / Include PreRelease / Instal-Package -Pre Ninject.Web.Common版本没有明确的解释。 我将把它翻译成Ninject.Extensions.NamedScope wiki中的一篇文章,在某个阶段已经开始在Ninject.Extensions.NamedScope wiki的CreateNamedScope / GetScope文章中编写这种技术的演练。

可能有些位也会在某个阶段变成拉取请求(提示给@Remo Gloor谁给了我大纲代码)。 相关的testing和学习testing目前正处于这个要点中 ),等待包装成适当的发布格式TBD。

执行摘要是你加载下面的模块到您的内核和使用.InRequestScope()在你想创build的一切/ Dispose d处理程序调用,然后通过IHandlerComposer.ComposeCallDispose提供请求。

如果您使用以下模块:

 public class Module : NinjectModule { public override void Load() { Bind<IHandlerComposer>().To<NinjectRequestScopedHandlerComposer>(); // Wire it up so InRequestScope will work for Handler scopes Bind<INinjectRequestHandlerScopeFactory>().To<NinjectRequestHandlerScopeFactory>(); NinjectRequestHandlerScopeFactory.NinjectHttpApplicationPlugin.RegisterIn( Kernel ); } } 

Factory [1]和NinjectHttpApplicationPlugin中的哪些线路公开:

 public interface INinjectRequestHandlerScopeFactory { NamedScope CreateRequestHandlerScope(); } 

然后,您可以使用此Composer来运行请求InRequestScope()

 public interface IHandlerComposer { void ComposeCallDispose( Type type, Action<object> callback ); } 

实现为:

 class NinjectRequestScopedHandlerComposer : IHandlerComposer { readonly INinjectRequestHandlerScopeFactory _requestHandlerScopeFactory; public NinjectRequestScopedHandlerComposer( INinjectRequestHandlerScopeFactory requestHandlerScopeFactory ) { _requestHandlerScopeFactory = requestHandlerScopeFactory; } void IHandlerComposer.ComposeCallDispose( Type handlerType, Action<object> callback ) { using ( var resolutionRoot = _requestHandlerScopeFactory.CreateRequestHandlerScope() ) foreach ( object handler in resolutionRoot.GetAll( handlerType ) ) callback( handler ); } } 

Ninject基础设施的东西:

 class NinjectRequestHandlerScopeFactory : INinjectRequestHandlerScopeFactory { internal const string ScopeName = "Handler"; readonly IKernel _kernel; public NinjectRequestHandlerScopeFactory( IKernel kernel ) { _kernel = kernel; } NamedScope INinjectRequestHandlerScopeFactory.CreateRequestHandlerScope() { return _kernel.CreateNamedScope( ScopeName ); } /// <summary> /// When plugged in as a Ninject Kernel Component via <c>RegisterIn(IKernel)</c>, makes the Named Scope generated during IHandlerFactory.RunAndDispose available for use via the Ninject.Web.Common's <c>.InRequestScope()</c> Binding extension. /// </summary> public class NinjectHttpApplicationPlugin : NinjectComponent, INinjectHttpApplicationPlugin { readonly IKernel kernel; public static void RegisterIn( IKernel kernel ) { kernel.Components.Add<INinjectHttpApplicationPlugin, NinjectHttpApplicationPlugin>(); } public NinjectHttpApplicationPlugin( IKernel kernel ) { this.kernel = kernel; } object INinjectHttpApplicationPlugin.GetRequestScope( IContext context ) { // TODO PR for TrgGetScope try { return NamedScopeExtensionMethods.GetScope( context, ScopeName ); } catch ( UnknownScopeException ) { return null; } } void INinjectHttpApplicationPlugin.Start() { } void INinjectHttpApplicationPlugin.Stop() { } } }