在我的服务层上,我在构造函数中注入了UnitOfWork
和2个存储库。工作单元和存储库有一个DbContext
的实例,我希望在这两个实例之间共享。我怎么能用Ninject做到这一点?应该考虑哪个范围?
我不在网络应用程序中所以我无法使用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的控制台应用程序架构。
让我们说:
A类是服务层类
B类是一个工作单元,它接受参数接口(IContextFactory)
C类是一个存储库,它接受参数接口(IContextFactory)
这里的想法是能够在2个或更多存储库上执行上下文操作,并使用工作单元来应用更改。
D类是一个上下文工厂(实体框架),它提供了一个实例(保存在容器中)的上下文,它在B类和C类之间共享(..也适用于其他存储库)。
上下文工厂将实例保存在他的容器中,所以我不想重复使用这个实例的所有名称,因为上下文需要在服务操作结束时处理..实际上是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");
答案 0 :(得分:5)
更新:这种方法对NuGet当前有效,但是在InCallscope
实现中存在一个异常现象,该异常已在当前的Unstable NuGet包中修复。我会在几天内调整这个答案,以反映一些仔细研究后的最佳方法。注意,构建内容的高级方式将保持完全相同,只需Bind<DbContext>()
范围确切的详细信息即可。 (提示:不稳定中的CreateNamedScope
会起作用,或者可以将命令处理程序设置为DefinesNamedScope
。原因我不这样做是因为我希望能够创建一些与{{1}组合/播放良好的内容})
我强烈建议您阅读InRequestScope
集成测试(严肃地说,找到它们并阅读并重新阅读它们)
Ninject.Extensions.NamedScope
是工作单位,因此无需进一步换行。
由于您希望能够在飞行中拥有多个“请求”并希望在它们之间共享一个工作单元,您需要:
DbContext
Bind<DbContext>()
.ToMethod( ctx =>
new DbContext(
connectionStringName: ConfigurationUtility.GetConnectionString() ))
.InCallScope();
表示:
InCallScope()
调用(因此在调用范围内)组成的给定对象图,需要kernel.Get()
的所有人都将获得相同的实例。DbContext
。IDisposable
将在根对象发生Dispose()
时调用(如果根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();
}
}
Command实现如下:
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>()
上使用Func<DbContext>
(但需要Ninject.Extensions.Factory
's FactoryModule
的存在才能从简单的Bind<DbContext>()
合成{{1}}。< / p>
答案 1 :(得分:2)
如the other answer中所述,InCallScope
不是解决此问题的好方法。
目前我正在转发一些代码,这些代码违反最新的NuGet Unstable / Include PreRelease / Instal-Package -Pre
版本的Ninject.Web.Common
,但没有明确的解释。我会将此翻译为已开始在the Ninject.Extensions.NamedScope
wiki中某篇文章Ninject.Extensions.NamedScope
wiki's CreateNamedScope/GetScope article中编写此技术的演练。
可能某些位也会在某个阶段成为Pull Request(给我提供大纲代码的@Remo Gloor)。 associated tests and learning tests are in this gist for now),待处理的包装以正确发布的格式TBD。
exec摘要是您将下面的模块加载到内核中,并在每个处理程序调用上使用.InRequestScope()
/ Dispose
每个处理程序调用,然后通过IHandlerComposer.ComposeCallDispose
提供请求。< / p>
如果您使用以下模块:
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();
}
然后您可以使用此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 Infrastructure的东西:
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()
{
}
}
}