由于异步,在 WebApi 中使用 HttpContext.Current 是危险的 [英] Using HttpContext.Current in WebApi is dangerous because of async

查看:25
本文介绍了由于异步,在 WebApi 中使用 HttpContext.Current 是危险的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与此有点相关:HttpContext 的 WebApi 等效项. 依赖注入的项目.

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

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

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

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

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

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

  4. 为了创建将内容注入构造函数的控制器IHttpControllerActivatorsync 方法IHttpController Create 一起使用.这就是 ninject 创建 Controller 及其所有依赖项的地方.


  • 如果我在所有这 4 点中都正确,在操作方法或下面的任何层中使用 HttpContext.Current 是非常危险的,并且可能会产生意想不到的结果.我在 StackOverflow 上看到很多公认的答案都暗示了这一点.在我看来,这可以工作一段时间,但会在负载下失败.

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

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

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

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

解决方案

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

HttpContext 应用于线程会更正确;或者一个线程进入"HttpContext.

<块引用>

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

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

<小时>

其中的关键是 SynchronizationContext.如果您不熟悉,我有一篇有关该主题的 MSDN 文章.SynchronizationContext 为平台定义了一个上下文",常见的有 UI 上下文(WPF、WinPhone、WinForms 等)、线程池上下文和 ASP.NET 请求上下文.>

ASP.NET 请求上下文管理 HttpContext.Current 以及其他一些内容,例如文化和安全性.UI 上下文都与单个线程( 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.Current等待,无需担心.

My question is a bit related to this: WebApi equivalent for HttpContext.Items with Dependency Injection.

We want to inject a class using HttpContext.Current in WebApi area using Ninject.

My concern is, this could be very dangerous, as in WebApi (everything?) is async.

Please correct me if I am wrong in these points, this is what I investigated so far:

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

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

  3. WebApi uses IHttpController with method Task<HttpResponseMessage> ExecuteAsync => every request is async => you cannot use HttpContext.Current inside of action method. It could even happen, more Request are executed on the same thread by coicidence.

  4. For creating controllers with injected stuff into constructors IHttpControllerActivator is used with sync method IHttpController Create. This is, where ninject creates Controller with all its dependencies.


  • If I am correct in all of these 4 points, using of HttpContext.Current inside of an action method or any layer below is very dangerous and can have unexpected results. I saw on StackOverflow lot of accepted answers suggesting exactly this. In my opinion this can work for a while, but will fail under load.

  • But when using DI to create a Controller and its dependencies, it is Ok, because this runs on one separated thread. I could get a value from the HttpContext in the constructor and it would be safe?. I wonder if each Controller is created on single thread for every request, as this could cause problem under heavy loads, where all threads from IIS could be consumed.

Just to explain why I want to inject HttpContext stuff:

  • one solution would be to get the request in controller action method and pass the needed value all the layers as param until its used somewhere deep in the code.
  • our wanted solution: all the layers between are not affected by this, and we can use the injected request somewhere deep in code (e.g. in some ConfigurationProvider which is dependent on URL)

Please give me your opinion if I am totally wrong or my suggestions are correct, as this theme seems to be very complicated.

解决方案

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

It would be more correct to say that HttpContext is applied to a thread; or a thread "enters" the HttpContext.

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

Not at all; the default behavior of async/await will resume on an arbitrary thread, but that thread will enter the request context before resuming your async method.


The key to this is the SynchronizationContext. I have an MSDN article on the subject if you're not familiar with it. A SynchronizationContext defines a "context" for a platform, with the common ones being UI contexts (WPF, WinPhone, WinForms, etc), the thread pool context, and the ASP.NET request context.

The ASP.NET request context manages HttpContext.Current as well as a few other things such as culture and security. The UI contexts are all tightly associated with a single thread (the UI thread), but the ASP.NET request context is not tied to a specific thread. It will, however, only allow one thread in the request context at a time.

The other part of the solution is how async and await work. I have an async intro on my blog that describes their behavior. In summary, await by default will capture the current context (which is SynchronizationContext.Current unless it is null), and use that context to resume the async method. So, await is automatically capturing the ASP.NET SynchronizationContext and will resume the async method within that request context (thus preserving culture, security, and HttpContext.Current).

If you await ConfigureAwait(false), then you're explicitly telling await to not capture the context.

Note that ASP.NET did have to change its SynchronizationContext to work cleanly with async/await. You have to ensure that the application is compiled against .NET 4.5 and also explicitly targets 4.5 in its web.config; this is the default for new ASP.NET 4.5 projects but must be explicitly set if you upgraded an existing project from ASP.NET 4.0 or earlier.

You can ensure these settings are correct by executing your application against .NET 4.5 and observing SynchronizationContext.Current. If it is AspNetSynchronizationContext, then you're good; if it's LegacyAspNetSynchronizationContext, then the settings are wrong.

As long as the settings are correct (and you are using the ASP.NET 4.5 AspNetSynchronizationContext), then you can safely use HttpContext.Current after an await without worrying about it.

这篇关于由于异步,在 WebApi 中使用 HttpContext.Current 是危险的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆