multithreading - 由于异步,在 WebApi 中使用 HttpContext.Current 是危险的

标签 multithreading asynchronous asp.net-web-api ninject httpcontext

我的问题与此有点相关:WebApi equivalent for HttpContext.Items with Dependency Injection .

我们希望使用 Ninject 在 WebApi 区域中使用 HttpContext.Current 注入(inject)一个类。

我担心的是,这可能非常危险,因为在 WebApi 中(一切?)都是异步的。

如果我在这些方面有误,请纠正我,这是我迄今为止调查的内容:

  1. HttpContext.Current通过Thread获取当前上下文(我直接查看了实现)。

  2. 在异步任务中使用 HttpContext.Current 是不可能的,因为它可以在另一个线程上运行。

  3. WebApi 使用 IHttpController 方法 Task<HttpResponseMessage> ExecuteAsync =>每个请求都是异步的=>你不能在action方法中使用HttpContext.Current。甚至有可能发生,更多的请求在同一个线程上巧合地执行。

  4. 用于创建 Controller 并将内容注入(inject)到构造函数中 IHttpControllerActivator同步方法一起使用IHttpController Create 。这是 ninject 创建 Controller 及其所有依赖项的地方。

<小时/>
  • 如果我在所有这 4 点上都是正确的,则使用 HttpContext.Current操作方法内部或下面的任何层都是非常危险的,可能会产生意想不到的结果。我在 StackOverflow 上看到很多已接受的答案都表明了这一点。在我看来,这可以工作一段时间,但在负载下会失败。

  • 但是当使用 DI 创建 Controller 及其依赖项时,就可以了,因为它运行在一个单独的线程上。 我可以从构造函数中的 HttpContext 获取一个值,这会安全吗?。我想知道是否每个 Controller 都是在每个请求的单线程上创建的,因为这可能会在重负载下导致问题,其中来自 IIS 的所有线程都可能被消耗。

只是为了解释为什么我想注入(inject) HttpContext 的东西:

  • 一种解决方案是在 Controller 操作方法中获取请求,并将所需的值作为参数传递给所有层,直到在代码深处的某个地方使用它。
  • 我们想要的解决方案:之间的所有层都不受此影响,我们可以在代码深处的某个位置使用注入(inject)的请求(例如在某些依赖于 URL 的 ConfigurationProvider 中)

如果我完全错误或者我的建议是正确的,请给我你的意见,因为这个主题似乎非常复杂。

最佳答案

HttpContext.Current gets the current context by Thread (I looked into the implementation directly).

更正确的说法是 HttpContext应用于线程;或者线程“进入”HttpContext .

Using HttpContext.Current inside of async Task is not possible, because it can run on another Thread.

完全没有; async 的默认行为/await将在任意线程上恢复,但该线程将在恢复您的 async 之前进入请求上下文。方法。

<小时/>

关键是SynchronizationContext 。我有一个MSDN article on the subject如果你不熟悉它。一个SynchronizationContext为平台定义“上下文”,常见的是 UI 上下文(WPF、WinPhone、WinForms 等)、线程池上下文和 ASP.NET 请求上下文。

ASP.NET 请求上下文管理HttpContext.Current以及其他一些事情,例如文化和安全。 UI 上下文都与单个线程(UI 线程)紧密关联,但 ASP.NET 请求上下文不与特定线程绑定(bind)。然而,它一次只允许请求上下文中有一个线程

解决方案的另一部分是如何asyncawait工作。我有一个 async intro on my blog that describes their behavior 。总之,await默认情况下将捕获当前上下文(除非是 SynchronizationContext.Current ,否则为 null ),并使用该上下文恢复 async 。方法。所以,await正在自动捕获 ASP.NET SynchronizationContext并将恢复 async该请求上下文中的方法(从而保留文化、安全性和 HttpContext.Current )。

如果您await ConfigureAwait(false) ,那么你明确地告诉 await 捕获上下文。

请注意,ASP.NET 确实必须更改其 SynchronizationContextasync一起干净地工作/await 。您必须确保应用程序是针对 .NET 4.5 和 also explicitly targets 4.5 in its web.config 进行编译的。 ;这是新 ASP.NET 4.5 项目的默认设置,但如果您从 ASP.NET 4.0 或更早版本升级现有项目,则必须显式设置。

您可以通过针对 .NET 4.5 执行应用程序并观察 SynchronizationContext.Current 来确保这些设置正确。 。如果是AspNetSynchronizationContext ,那你就很好了;如果是LegacyAspNetSynchronizationContext ,则说明设置错误。

只要设置正确(并且您使用的是 ASP.NET 4.5 AspNetSynchronizationContext ),那么您就可以安全地使用 HttpContext.Current 。在await之后不用担心。

关于multithreading - 由于异步,在 WebApi 中使用 HttpContext.Current 是危险的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24956178/

相关文章:

python - 如何在python中的多个线程之间正确共享信息?

c# - 在串行端口的 DataReceived 事件处理程序中读取数据时尝试显示文本时出现死锁

javascript - 异步回调不会被调用

php - PHP 可以异步使用套接字吗?

c# - 如何在我的 JSON 模型类中使用保留关键字作为标识符?

mysql - MySQL最大连接数,适当关闭连接

java - 让线程无限期等待

php - Laravel 作业不是异步的

c# - Owin/Katana 应该取代 Web API 吗?

WCF + web api + 无法建立连接,因为目标机器主动拒绝它 x.x.x.x :443