寻找表现得像一个InRequestScope范围Ninject(Looking for a Ninj

2019-07-23 02:00发布

在我服务层我已经注入了UnitOfWork和2个仓库在构造函数中。 工作和存储库的单位有一个实例DbContext我想他们两个人之间的共享。 我如何能做到这一点与Ninject? 其范围应被考虑?

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

我试图做同样的事情......但是和我使用DI,我需要我的UOW是Dispose d和这样的创造。

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

    uow.SaveChanges();
}

编辑:我只是想知道我知道......看后https://github.com/ninject/ninject.extensions.namedscope/wiki/InNamedScope我虽然哪些实际使用Ninject我目前的控制台应用程序架构。

比方说:

类是一服务层类

B类是工作的一个单元,其考虑到参数的接口(IContextFactory)

C类是一个储存库,其考虑到参数的接口(IContextFactory)

这里的想法是要能够做2个或多个存储库和使用工作的单位以应用更改上下文操作。

d类是一个上下文工厂(实体框架),它提供一个实例(保持在容器中),其被B类等℃之间共享的上下文的(..和将成为其他存储库藏汉)。

上下文工厂保持比如在他的容器,所以我不想因为上下文需要在服务operaiton年底被安置..它是InNamedScope实际上的主要目的重用这种情况下所有的名字吗?

解决办法是,但我不知道在我的全部做的是正确的服务实例会被transcient这意味着他们却从未配置? :

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");

Answer 1:

更新:这种方法适用反对的NuGet电流,但依靠在异常InCallscope已被固定在当前不稳定的NuGet包实现。 我将在几天内调整这个答案,以反映最好的办法经过一番思索。 NB的结构材料的高层次的方式将保持几乎相同,只是确切的细节Bind<DbContext>()作用域会工作。 (提示: CreateNamedScope不稳定会工作或一个可以设置命令处理程序DefinesNamedScope 。我之所以不只是做到这一点的是,我想有一些组成/有打得很好InRequestScope


我强烈建议你阅读的Ninject.Extensions.NamedScope集成测试(严重的是,找到他们,阅读和重新阅读)

DbContext 一个单位工作,所以没有进一步的包装是必要的。

当你希望能够有多个“要求”在飞行中,并希望有它们之间共享一个单独的工作单位,您需要:

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

所述InCallScope()表示:

  1. 对于一个由给定对象图kernel.Get() 调用 (因此,在呼叫范围),每个人都需要一个DbContext会得到相同的实例。
  2. IDisposableDispose()时,将被称为Kernel.Release()发生根对象(或Kernel.Components.Get<ICache>().Clear()发生根如果它不是.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();
    }
}

注意,一般来说,我避免在这种方式工作的隐式单位,而是表面它的创建和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();
        }
   }

这涉及到的无用法.InCallScope()Bind<DbContext>()但是需要的存在Ninject.Extensions.FactoryFactoryModule合成Func<DbContext>从一个简单的Bind<DbContext>()



Answer 2:

正如在讨论对方的回答 , InCallScope是不是一个好的方法来解决这个问题。

现在我倾倒一些代码,针对最新的NuGet不稳定工作/包括抢鲜/ Instal-Package -Pre的版本Ninject.Web.Common没有一个明确的解释。 我会翻译这在一篇文章Ninject.Extensions.NamedScope在某个阶段维基已经开始写这种技术的演练中Ninject.Extensions.NamedScope维基CreateNamedScope / GetScope文章 。

可能还有一些位将成为在某一阶段上拉请求(S)太(帽尖到@Remo Gloor谁给我提供了大纲代码)。 在相关的测试和学习测试是在这个要点现在 ),等待以适当的格式发布TBD包装。

这位经理总结为您加载模块下方进内核,并使用.InRequestScope()上的一切你想创建/ 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 );
    }
}

其中导线在工厂[1]和NinjectHttpApplicationPlugin暴露:

public interface INinjectRequestHandlerScopeFactory
{
    NamedScope CreateRequestHandlerScope();
}

然后你可以使用这个作曲家运行请求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()
        {
        }
    }
}


文章来源: Looking for a Ninject scope that behaves like InRequestScope