"HttpContext.Current"属性和相关内容的跨线程用法

smw*_*dia 38 asp.net multithreading

我从<Essential ASP.NET with C#中的示例>中读取以下语句:

另一个有用的属性是HttpContext类的静态Current属性.此属性始终指向要提供服务的请求的HttpContext类的当前实例.如果您正在编写将从页面或其他管道类中使用的辅助类,并且可能因任何原因需要访问上下文,这可能很方便.通过使用静态Current属性来检索上下文,可以避免将对它的引用传递给辅助类.例如,清单4-1中显示的类使用上下文的Current属性来访问QueryString并将内容打印到当前响应缓冲区.请注意,要正确初始化此静态属性,调用方必须在原始请求线程上执行,因此如果您在请求期间生成了其他线程来执行工作,则必须注意自己提供对上下文类的访问.

我想知道大胆部分的根本原因,有一件事导致另一件事,这是我的想法:

我们知道一个进程可以有多个线程.这些线程中的每一个分别具有它们自己的堆栈.这些线程还可以访问共享内存区域堆.

然后,根据我的理解,堆栈是存储该线程的所有上下文的地方.对于访问堆中某些东西的线程,它必须使用指针,并且指针存储在其堆栈中.

因此,当我们进行一些跨线程调用时,我们必须确保所有必要的上下文信息都从调用者线程的堆栈传递到被调用者线程的堆栈.

但我不确定我是否犯了任何错误.

任何评论都将深表感谢.

谢谢.

这里堆栈仅限于用户堆栈.

Mar*_*ker 80

有四件事情共同导致您所询问的行为:

  1. HttpContext是一个实例对象,可以在其中找到引用 HttpContext.Current
  2. Thread也是一个实例对象,可以在其中找到引用 Thread.CurrentThread
  3. Thread.CurrentThread是静态的,但Thread在每个线程中引用一个不同的对象
  4. HttpContext.Current 实际上指向 Thread.CurrentThread.ExecutionContext.IllogicalCallContext.HostContext

结论我们可以从以上给出:

  1. 因为它HttpContext是一个实例对象而不是静态的,我们需要它的引用来访问它
  2. 因为HttpContext.Current实际上指向属性Thread.CurrentThread,更改Thread.CurrentThread为不同的对象可能会更改HttpContext.Current
  3. 因为Thread.CurrentThread切换线程时更改,切换线程时HttpContext.Current 也会发生变化(在这种情况下HttpContext.Current变为空).

将所有这些结合在一起,是什么原因导致HttpContext.Current无法在新线程中工作?Thread.CurrentThread切换线程时发生的引用更改会更改HttpContext.Current引用,这会阻止我们进入我们想要的HttpContext实例.

重申一下,这里唯一的神奇之处就是Thread.CurrentThread在每个Thread中引用一个不同的对象.HttpContext就像任何其他实例对象一样工作.由于同一AppDomain中的线程可以引用相同的对象,我们所要做的就是将HttpContext的引用传递给我们的新线程.没有加载的上下文信息或类似的东西.(将HttpContext传递给其他线程有一些相当严重的潜在问题,但没有什么可以阻止你这样做).

我在研究时遇到的一些最后的附注:

  1. 在某些情况下,Thread的ExecutionContext从一个Thread"流"(复制)到另一个Thread.那么为什么HttpContext没有"流"到我们的新线程?因为HttpContext没有实现ILogicalThreadAffinative接口.存储在ExecutionContext中的类只有在实现ILogicalThreadAffinative时才会流动.

  2. 如果没有流动,ASP.NET如何将HttpContext从线程移动到线程(线程敏捷)?我不完全确定,但看起来它可能会传递它HttpApplication.OnThreadEnter().

  • 我想OP自从29日以来他没有登录就没有回来奖励赏金,所以我认为你应该获得这个非常彻底的答案的自动奖励.+1让你站在最前面.:) (3认同)
  • 题外话,但我喜欢你称之为 IllogicContext(它太多了,具有喜剧效果)。 (2认同)

Tud*_*dor 10

我想我在这里找到了一个合适的解释:http://odetocode.com/articles/112.aspx

总而言之,代码隐藏HttpContext.Current看起来像这样:

public static HttpContext get_Current()
{ 
    return (CallContext.GetData("HtCt") as HttpContext); 
}
Run Code Online (Sandbox Code Playgroud)

CallContext作为线程本地存储一起运行(即每个线程将看到不同的数据副本,并且无法访问其他线程看到的副本).因此,一旦在一个线程上初始化当前上下文,其他线程的后续访问将导致a NullReferenceException,因为该属性是初始线程的线程本地.

所以是的,你的初步解释很接近,因为数据只对单个线程可见是一个问题.