HttpContext.Current 如何处理 IIS 管道中的每个请求?

How HttpContext.Current works on each request in IIS pipeline?

如您所知,HttpContext.Current returns 应用程序管道中的当前上下文。
此外,此 属性 是 static,因此从逻辑上讲,对其或其属性的任何更改都应影响其他管道。

A static field identifies exactly one storage location. No matter how many instances of a class are created, there is only ever one copy of a static field. More

IIS 如何处理此问题以防止在其他管道上发生冲突并且每个 HttpContext.Current 在每个管道上都是唯一的?

例如,对于已经登录系统的两个用户,HttpContext.Current.User.Identity.Name 给出向服务器发送请求的用户的用户名。

ASP.NET管道:

Current是属性,不是字段,所以它实际上是一个静态方法。

此方法可以 return 不同线程的不同实例,而且确实如此。

如果您正在开发多线程 Web 应用程序,请记住以下几点。

  1. 不要使用 ThreadStaticAttribute。它适用于 Windows 和控制台应用程序,但它可能不适用于 Web 应用程序,因为单个请求可以由不同的线程处理,如果您使用 asyncawaitTask<T>.

  2. 使用 HttpContext.Current.Items 而不是 ThreadStaticAttribute。这些Items在每个HttpContext中是"static"。

  3. 如果您在异步调用后需要 HttpContext 的重要设置(区域设置、登录用户和您自己的 HttpContext.Items),请使用 SynchronizationContext(如果您没有使用 await).

你要小心的原因是线程池。您的异步方法很可能在第一个线程中开始 运行,在第二个线程中继续,并在第三个线程中结束。由于每个线程都有自己的线程静态字段副本,您可以在方法的不同位置获得不可预知的不同字段值。 SynchronizationContext 允许您 return 使用正确的区域设置值 HttpContext.Items 等初始线程。 await 运算符对您有用,所以您不应该关心上下文,如果你使用 await(感谢@StephenCleary 的更正)。

现在是线程静态字段。当 ASP.NET 收到 HTTP 请求时,它会创建带有空 HttpContext.Items 集合的 HttpContext 的新实例。同时 ThreadStatic 字段已由先前的 HTTP 请求初始化。因此f.e。 a Singleton class,基于线程静态字段可能无法正常工作。它在 Web 应用程序的同步和异步方法中都很重要。

答案在于线程本地存储,在 .NET 中使用 ThreadStatic 实现。环境上下文设计模式也与此相关。