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

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

问题描述

我的问题是与此相关的一个位:<一href=\"http://stackoverflow.com/questions/23395632/webapi-equivalent-for-httpcontext-items-with-dependency-injection\">WebApi相当于HttpContext.Items与依赖注入。

我们希望使用Ninject中的WebAPI地区使用HttpContext.Current注入一类。

我关心的是,这可能是的非常危险,如的WebAPI(的一切吗?的)是异步。

请纠正我,如果我错了,在这点,这是我调查至今:


  1. HttpContext.Current获得通过线程的当前上下文(我看着进入实施直接)。


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


  3. 的WebAPI使用IHttpController与方法任务&LT; Htt的presponseMessage&GT; ExecuteAsync =>每一个请求是异步=>您不能使用HttpContext.Current操作方法里面。它甚至可能发生,更多的请求被coicidence相同的线程上执行。


  4. 有关注射的东西创建控制器为构造IHttpControllerActivator用于与同步方式 IHttpController创建。这一点,在那里与ninject其所有的依赖造成控制器。




  • 如果我在所有这些4点正确,操作方法或任何层内部使用HttpContext.Current下面是非常危险的,可以有意想不到的效果。我看到很多SO接受的答案正是这种提示的。恕我直言,这可以工作了一段时间,但在负载下会失败。


  • 但使用DI创建一个控制器及其依赖的时候,它是确定的,因为这个运行在一个独立的线程。 我可以摆脱在构造函数中的HttpContext值,这将是安全的吗?。我不知道如果在单个线程创建为每个请求的每个控制器,因为这可能重物,其中从IIS中的所有线程可以消耗下造成的问题。


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


  • 一个解决办法是让在控制器的操作方法的要求,并通过所需要的价值的所有图层作为参数,直到它在code使用深的地方。

  • 我们的解决方案通缉:所有的层不受此受其影响,我们可以在code深的地方使用注入的请求(例如,在一些ConfigurationProvider这是依赖于URL)

    请给我你的意见,如果我错了完全以我还是建议是正确的,因为这个主题似乎是很复杂的。 Thx提前!



解决方案

  

HttpContext.Current获得通过线程的当前上下文(我看着进入实施直接)。


这将是更正确地说,的HttpContext 应用于螺纹;或线程进入的HttpContext


  

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


也没有。 的异步的默认行为 / 等待将恢复在任意的线程,但该线程将在恢复之前输入的请求上下文你的异步方法。


解决这个问题的关键是的SynchronizationContext 。我有,如果你不熟悉它的主题的 MSDN文章。 A 的SynchronizationContext 定义了一个平台背景,与常用的是UI上下文(WPF,WinPhone,的WinForms,等等),线程池上下文,ASP。 NET请求上下文。

ASP.NET请求范围内管理着 HttpContext.Current 以及一些其他的东西,如文化,安全。用户界面背景都紧密地与一个单独的线程( UI线程)有关,但ASP.NET请求上下文没有绑定到特定的线程。它将,但是,只允许在请求上下文一个线程的一次

解决方案的另一部分是如何异步的await 的工作。我在我的博客上 异步简介,介绍了他们的行为。综上所述,等待默认情况下,将捕捉到的当前环境(即 SynchronizationContext.Current ,除非它是无效),并使用该上下文来恢复异步方法。因此,等待自动捕获ASP.NET 的SynchronizationContext 键,将恢复异步的请求上下文(因此preserving文化,安全和 HttpContext.Current )。

中的方法

如果您等待 ConfigureAwait(假),那么你就明确地告诉等待来的的捕捉环境。

注意,ASP.NET确实有改变其的SynchronizationContext 异步 / <$ C $干净工作C>等待。你必须确保应用程序针对.NET 4.5和<编译href=\"http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx\">also明确针对4.5在web.config中;这是一个新的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 SO lot of accepted answers suggesting exactly this. IMHO 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 afected by this, and we can use the injected request somewhere deep in code (eg in some ConfigurationProvider which is dependent on URL)

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

解决方案

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天全站免登陆