异步任务中的HttpContext.Current null

时间:2013-10-01 08:17:22

标签: c# ninject async-await httpcontext

我有一个使用存储库(userRepo)的方法:

    public override Task<IdentityResult> CreateLocalUserAsync(IUser user, string password, CancellationToken cancellationToken)
    {
        var task = new Task<IdentityResult>(() => {

            TUserEntity newUser = new TUserEntity
            {
                Id = user.Id,
                UserName = user.UserName,
                Password = password
            };

            userRepo.Save(newUser).Flush();

            return new IdentityResult(true);
        }, cancellationToken);

        task.Start();

        return task;
    }

userRepo对象具有使用HttpContext.Current的依赖项。使用ninject InRequestScope解决了这两个问题。

在Mvc 5中的默认AccountController内调用上述方法:

var result = await IdentityManager.Users.CreateLocalUserAsync(user, model.Password);

我尝试将此设置添加到web.config:

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

另外,我肯定使用的是.NET 4.5。这也在我的web.config中:

<httpRuntime targetFramework="4.5" />

在开始任务之前无法从HttpContext获取信息,因为任务中userRepo的依赖关系正在使用信息,并且使用Ninject解析了两个对象。

如何确保HttpContext.Current不为空?

1 个答案:

答案 0 :(得分:16)

此处的“任务友好同步上下文”适用于await的延续:无论您使用result做什么,它都将具有http上下文。但task.Start有关。这与TaskScheduler有关,而不是同步上下文。

基本上,通过对工作人员执行此操作,您(在此过程中)将该工作人员与http上下文分开。你必须:

  • 从http-context获取所需信息,并将传递给工作者,或
  • 不要使用工人

就个人而言,我怀疑你是通过将其推向一名工人而获得的。如果您真的想要async,那么理想情况是您的回购内部支持*Async方法。这需要的不仅仅是使用线程:它通常意味着架构更改,例如,使用异步SQL方法。从头开始编写使用async和同步上下文感知延续(又名await)的东西会自动保留像http上下文这样的内容。

这里的重要区别是async / await实现是线性的但不是连续的,即

 <===(work)==>
                    <===(callback; more work)===>
                                                     <===(another callback)===>

其中 - 因为您现有的代码可能会并行执行 ,即

<==========(original work)=================>
         <===========(task on worker thread)=============>

async / await方法基本线性的事实使得它更适合访问像http-context这样的东西,因为它知道(做得对)一次只有一个线程访问它 - 即使它不是端到端的相同线程。