Ninject和异步操作

时间:2014-09-14 16:03:37

标签: c# asp.net asp.net-mvc asynchronous ninject

我现在一直在谷歌上寻找有关如何将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 };

那么,有没有办法解决这个问题&#34; easy&#34;方式是什么?

2 个答案:

答案 0 :(得分:3)

这就是你自己如何控制对象的创建:

public interface IContextFactory {
    MyContext Create();
}

kernel.Bind<IContextFactory>().ToFactory // requires ninjext.extensions.factory

Factory Extension Link

用法:

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 contextual binding

答案 1 :(得分:1)

经过一些挖掘和阅读本帖后其他用户的回复,我意识到这不是一个简单的方法。

所以我决定使用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 };
}

它可能不是那么整洁,但是它有效并且我看不到任何缺点(除了初始块和处理它的一些小的性能问题)。