Ninject和异步操作
本文关键字:异步操作 Ninject | 更新日期: 2023-09-27 18:21:53
我已经在谷歌上搜索了一些关于如何将Ninject与异步/等待操作一起使用的有用示例。我自己也尝试过,在不需要写很多代码的情况下,找到任何可以让它真正工作的模式,但我还没有成功。
对基本问题最简单的描述是,实体框架DbContext
是在每个请求范围的基础上创建的(它是一个ASP.NET MVC应用程序),但如果你试图调用任何*Async
方法,它都会失败,并显示它已经在执行了(这很明显)。
因此,我需要的是调用Kernel.Get<MyContext>()
使用Ninject创建唯一的DbContext
对象,并且由Ninject负责其生命周期。使用BeginBlock()
或将作用域更改为InTransientScope()
并不是一个真正的选项,因为第一种方法会使代码变得非常沉重,并带有单独的块和处理这些块,而后者则将调用方代码设置为负责处理DbContext
。
我想做的代码的POC示例:
var context1 = NinjectKernelReference.Get<MyContext>(); //I want this to be a unique reference
var context2 = NinjectKernelReference.Get<MyContext>(); //I want this to be a unique reference
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
那么,有什么"简单"的方法可以解决这个问题吗?
这就是您自己控制对象创建的方法:
public interface IContextFactory {
MyContext Create();
}
kernel.Bind<IContextFactory>().ToFactory // requires ninjext.extensions.factory
(工厂扩展链路)
用法:
using(var context1 = IContextFactory.Create())
using(var context2 = IContextFactory.Create())
{
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
} // context get's disposed here
注意:这需要上下文而不是绑定.InRequestScope()
,否则,两个.Create()
调用都将返回相同的对象。如果有时需要.InRequestScope()
,有时不需要,可以考虑使用ninject上下文绑定
经过一些挖掘和阅读其他用户对这篇文章的回应,我意识到这不是一个简单的方法。
因此,我决定使用IKernel.BeginBlock
在并行线程执行中创建一个"本地"Ninject作用域,我在这里执行逻辑。
它可能没有我想要的那么整洁,但它很管用。
using( var block1 = NinjectKernelReference.BeginBlock())
using( var block2 = NinjectKernelReference.BeginBlock())
{
var context1 = block1.Get<MyContext>();
var context2 = block2.Get<MyContext>();
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
}
它可能没有那么整洁,但它很有效,我看不出有任何负面影响(除了BeginBlock和Dispose的一些小性能问题)。