在WebApi中使用HttpContext.Current是危险的,因为异步

Luk*_*s K 61 multithreading asynchronous ninject httpcontext asp.net-web-api

我的问题与此有点相关:具有依赖注入的HttpContext.Items的WebApi等价物.

我们想使用Ninject在WebApi区域中使用HttpContext.Current注入一个类.

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

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

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

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

  3. WebApi使用IHttpController和method Task<HttpResponseMessage> ExecuteAsync=>每个请求都是async =>你不能在action方法中使用HttpContext.Current.它甚至可能发生,更多的请求是通过相同的线程在同一个线程上执行的.

  4. 为了创建带有注入内容的控制器到构造函数中,IHttpControllerActivator与sync方法一起使用IHttpController Create.这是,ninject创建Controller及其所有依赖项.


  • 如果我在所有这4点中都是正确的,那么在动作方法或下面的任何层中使用HttpContext.Current是非常危险的,并且可能会产生意外结果.我看到很多公认的答案正是如此.恕我直言,这可以工作一段时间,但会在负载下失败.

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

只是为了解释为什么我要注入HttpContext的东西:

  • 一种解决方案是在控制器动作方法中获取请求,并将所有层的所需值作为参数传递,直到它在代码深处使用.
  • 我们想要的解决方案:它们之间的所有层都没有被这个感染,我们可以在代码深处使用注入的请求(例如在一些依赖于URL的ConfigurationProvider中)

    如果我完全错误或者我的建议是正确的,请告诉我你的意见,因为这个主题似乎非常复杂.Thx提前!

Ste*_*ary 99

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

说将HttpContext其应用于线程更为正确; 或者一个线程"进入" HttpContext.

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

一点也不; async/ 的默认行为await将在任意线程上恢复,但该线程将在恢复async方法之前进入请求上下文.


关键是这个SynchronizationContext.如果你不熟悉它,我有一篇关于这个主题MSDN文章.A SynchronizationContext为平台定义"上下文",常见的是UI上下文(WPF,WinPhone,WinForms等),线程池上下文和ASP.NET请求上下文.

ASP.NET请求上下文HttpContext.Current以及文化和安全等一些其他内容进行管理.用户界面的上下文都紧密地与一个线程相关联( UI线程),但ASP.NET请求上下文不依赖于特定的线程.但是,它一次只允许请求上下文中的一个线程.

该解决方案的另一部分是如何asyncawait工作.我async在我的博客上有一个描述他们行为的介绍.总之,await默认情况下将捕获当前上下文(SynchronizationContext.Current除非它是null),并使用该上下文来恢复该async方法.因此,await自动捕获ASP.NET SynchronizationContext并将async在该请求上下文中恢复该方法(从而保留文化,安全性和HttpContext.Current).

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

请注意,ASP.NET必须将其更改SynchronizationContext为使用async/ 干净地工作await.您必须确保应用程序是针对.NET 4.5编译的,并且还要在其web.config中明确指向4.5 ; 这是新ASP.NET 4.5项目的默认设置,但如果从ASP.NET 4.0或更早版本升级现有项目,则必须显式设置.

您可以通过针对.NET 4.5执行应用程序并观察来确保这些设置正确无误SynchronizationContext.Current.如果是AspNetSynchronizationContext,那你就是好人; 如果是的话LegacyAspNetSynchronizationContext,那么设置是错误的.

只要设置正确(和您正在使用ASP.NET 4.5 AspNetSynchronizationContext),那么你可以放心地使用HttpContext.Currentawait无需担心它.

  • @ScottGartner:仅在服务器端怪癖模式处于活动状态时才使用旧上下文.仅当您升级到.NET 4.5并且尚未关闭它时才会出现这种情况.对于新的.NET 4.5 ASP.NET项目,使用新上下文是默认设置.[更多信息在这里](http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx). (3认同)
  • @Stephen,谢谢你的回答.在我意识到我遇到的问题之前,我必须阅读它两次,而不是将`httpRuntime`设置为`4.5`.我一做到这一点,我的所有问题都消失了. (2认同)
  • @Mick:每个方法都选择捕获并恢复自己的上下文。如果被调用的方法丢弃其上下文,则不会影响调用者。如果调用者方法*在*调用该方法之后丢弃其上下文,则不会影响该方法。如果调用者方法*在*调用该方法之前丢弃其上下文,则该方法将不具有上下文。 (2认同)
  • @肖森:是的。这不是*推荐*(它仍然被认为是一个糟糕的设计),但它会起作用。 (2认同)

小智 6

我正在使用一个 web api,它使用 async/await 方法。

还使用

1) HttpContext.Current.Server.MapPath
2) System.Web.HttpContext.Current.Request.ServerVariables
Run Code Online (Sandbox Code Playgroud)

这在很长一段时间内运行良好,但由于没有代码更改而突然中断。

花了很多时间恢复到以前的旧版本,发现丢失的密钥导致了问题。

< httpRuntime targetFramework="4.5.2"  /> under system.web
Run Code Online (Sandbox Code Playgroud)

我不是技术专家。但我建议将密钥添加到您的网络配置中并给它一个GO