异步任务中的HttpContext.Current null

oro*_*edd 11 c# ninject httpcontext async-await

我有一个使用repository(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;
    }
Run Code Online (Sandbox Code Playgroud)

userRepo对象具有使用的依赖项HttpContext.Current.这两个都是使用ninject解决的InRequestScope.

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

var result = await IdentityManager.Users.CreateLocalUserAsync(user, model.Password);
Run Code Online (Sandbox Code Playgroud)

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

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
Run Code Online (Sandbox Code Playgroud)

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

<httpRuntime targetFramework="4.5" />
Run Code Online (Sandbox Code Playgroud)

HttpContext在我开始执行任务之前无法获取信息,因为任务中的依赖userRepo项正在使用信息,并且使用Ninject解析了这两个对象.

我怎样才能确保HttpContext.Current不会为空?

Mar*_*ell 16

这里的"任务友好同步上下文"适用于以下内容的延续await:无论您使用什么result,它都将具有http上下文.它并没有,但是,涉及到task.Start.这涉及到TaskScheduler,而不是同步上下文.

基本上,通过在工作者上执行此操作,您(在此过程中)将该工作者与http上下文分离.你必须:

  • 让你从HTTP上下文需要的信息,并传递工人,或
  • 不要使用工人

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

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

 <===(work)==>
                    <===(callback; more work)===>
                                                     <===(another callback)===>
Run Code Online (Sandbox Code Playgroud)

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

<==========(original work)=================>
         <===========(task on worker thread)=============>
Run Code Online (Sandbox Code Playgroud)

async/ awaitapproach 基本上是线性的这一事实使它更适合访问像http-context这样的东西,因为它知道(完成正确)一次只有一个线程访问它 - 即使它不是相同的线程端到端.