为什么在使用当前同步上下文启动任务时未设置ASP.NET HttpContext.Current

Fre*_*eek 20 .net asp.net asynchronous task-parallel-library

我正在玩一点.NET的异步功能,并提出了一个我无法解释的情况.在同步ASP.NET MVC控制器中执行以下代码时

var t = Task.Factory.StartNew(()=>{
        var ctx = System.Web.HttpContext.Current;
        //ctx == null here
},
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext()
);

t.Wait();
Run Code Online (Sandbox Code Playgroud)

ctxnull委托范围内.根据我的理解,当您使用TaskScheduler.FromCurrentSynchronizationContext()任务调度程序时,应该恢复上下文.那么为什么不在这里呢?(我可以,顺便说一下,看到委托在同一个线程上同步执行).

此外,从msdn,a TaskScheduler.FromCurrentSynchronizationContext()应该表现如下:

排队到返回的调度程序的所有Task实例将通过在该上下文上调用Post方法来执行.

但是,当我使用此代码时:

var wh = new AutoResetEvent(false);

SynchronizationContext.Current.Post(s=> {
    var ctx = System.Web.HttpContext.Current;
    //ctx is set here
    wh.Set();
    return;
},null);

wh.WaitOne();
Run Code Online (Sandbox Code Playgroud)

实际上设置了上下文.

我知道这个例子有点做作,但我真的很想了解如何增加我对.NET上异步编程的理解.

nmd*_*mdr 7

你的观察似乎是正确的,这有点令人费解. 您将调度程序指定为"TaskScheduler.FromCurrentSynchronizationContext()".这将关联一个新的"SynchronizationContextTaskScheduler".现在,如果你研究这个类,它使用: 在此输入图像描述

因此,如果任务调度程序可以访问相同的"同步上下文"并且应该引用"LegacyAspNetSychronizationContext".所以肯定看来HttpContext.current不应该为null.

在第二种情况下,当您使用SychronizationContext时(请参阅:MSDN文章),线程的上下文与任务共享:

"SynchronizationContext的另一个方面是每个线程都有一个"当前"上下文.线程的上下文不一定是唯一的;它的上下文实例可以与其他线程共享."


在这种情况下,SynchronacyContext.Current由LegacyAspNetSychronizationContext提供,并在内部具有对HttpApplication的引用.

当Post方法必须调用已注册的回调时,它会调用HttpApplication.OnThreadEnter,这最终会导致将当前线程的上下文设置为HttpCurrent.Context:

在此输入图像描述

这里引用的所有类都被定义为框架内部,并且使得进一步调查变得有点困难.

PS:说明SynchornizationContext对象实际上指向"LegacyAspNetSynchronizationContext": 在此输入图像描述


n.p*_*ski 1

我前段时间在谷歌上搜索 HTTPContext 信息。我发现了这个:

\n

http://odetocode.com/articles/112.aspx

\n

这是关于线程和 HTTPContext 的。有一个很好的解释:

\n
\n

CallContext 提供与线程本地存储极其相似的服务(除了 CallContext 可以在远程调用期间执行一些额外的魔法)。线程本地存储是一个概念,其中应用程序域中的每个逻辑线程都有一个唯一的数据槽来保存特定于其自身的数据。线程不共享数据,一个线程不能修改另一线程的本地数据。ASP.NET 在选择一个线程来执行传入请求后,会将当前请求上下文的引用存储在 thread\xe2\x80\x99s 本地存储中。现在,无论线程执行时去往何处(业务对象、数据访问对象),上下文都在附近并且可以轻松检索。

\n

知道上述内容后,我们可以声明以下内容:如果在处理请求时,执行移动到不同的线程(通过 QueueUserWorkItem 或异步委托,作为两个示例),HttpContext.Current 将不知道如何检索当前上下文,并且将返回 null。您可能认为解决该问题的一种方法是传递对工作线程的引用

\n
\n

因此,您必须通过某个变量创建对 HTTPContext.Current 的引用,并且该变量将从您将在代码中创建的其他线程中寻址。

\n