HttpContext.Current null inside async task



我有一个使用存储库的方法(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不会为空?

这里的"任务友好同步上下文"适用于await的延续:无论你用result做什么,它都会有http-context。但是,它task.Start无关。这与TaskScheduler有关,而不是同步上下文。

基本上,通过在worker上执行此操作,你(在这个过程中,因此(将该worker与http-context分离。您必须:

  • 从 HTTP 上下文中获取所需的信息并将其传递给工作线程,或者
  • 不要使用辅助角色

就我个人而言,我怀疑你把它推到工人身上会得到多少好处。如果你真的想去async,理想的情况是你的存储库在内部支持*Async方法。这需要的不仅仅是使用线程:它通常意味着架构更改,例如,使用异步SQL方法。从头开始编写的东西使用async和同步上下文感知延续(又名await(会自动保留像http-context这样的东西。

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

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

其中 - 由于您现有的代码可能并行执行,即

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

async/await方法基本上是线性的,这一事实使其更适合访问http-context之类的东西,因为它知道(正确完成(一次只有一个线程访问它 - 即使它不是同一个线程端到端。

最新更新