在WebApi中使用HttpContext.Current是非常危险的,因为是asynchronous的
我的问题是有点相关: WebApi相当于HttpContext.Items与dependency injection 。
我们要使用Ninject在WebApi区域中使用HttpContext.Current注入一个类。
我担心的是,这可能是非常危险的 ,因为在WebApi( 一切? )是asynchronous的。
请纠正我,如果我在这些问题上错了,这是我到目前为止调查:
-
HttpContext.Current通过线程获取当前上下文(我直接查看实现)。
-
使用HttpContext.Current里面的async Task是不可能的,因为它可以在另一个Thread上运行。
-
WebApi使用IHttpController和方法
Task<HttpResponseMessage> ExecuteAsync
=>每个请求都是async =>你不能使用HttpContext.Current里面的action方法。 它甚至可能发生,更多的请求由同一个线程执行。 -
创build控制器与注入东西到构造函数IHttpControllerActivator与同步方法
IHttpController Create
。 这是ninject创buildController的所有依赖项的地方。
-
如果我在所有这4点中都是正确的,那么在动作方法或下面的任何图层中使用HttpContext.Current是非常危险的,并且会有意想不到的结果。 我看到很多接受的答案,正是这个build议。 恕我直言,这可以工作一段时间,但会在负载下失败。
-
但是,当使用DI来创build一个控制器和它的依赖关系时,这是正常的,因为它运行在一个单独的线程上。 我可以从构造函数中的HttpContext获得一个值,这将是安全的? 。 我想知道是否每个控制器都是在单个线程上为每个请求创build的,因为这可能会导致在负载很重的情况下可能会消耗来自IIS的所有线程的问题。
只是为了解释为什么我要注入HttpContext的东西:
- 一个解决scheme是获取控制器操作方法中的请求,并将所有层的所需值作为parameter passing,直到在代码中深处使用。
-
我们想要的解决scheme:所有的层之间都不受此影响,我们可以在代码深处使用注入的请求(例如,在一些依赖于URL的ConfigurationProvider中)
如果我总是错误的或者我的build议是正确的,请给我你的意见,因为这个主题似乎是非常复杂的。 Thx提前!
HttpContext.Current通过线程获取当前上下文(我直接查看实现)。
说HttpContext
应用于一个线程是更正确的; 或者一个线程“进入” HttpContext
。
使用HttpContext.Current里面的async Task是不可能的,因为它可以在另一个Thread上运行。
一点也不; async
/ await
的默认行为将在任意线程上恢复,但是在恢复async
方法之前,该线程将进入请求上下文。
关键是SynchronizationContext
。 如果您不熟悉这个主题,我有关于这个主题的MSDN文章 。 一个SynchronizationContext
定义了一个平台的“上下文”,常用的是UI上下文(WPF,WinPhone,WinForms等),线程池上下文和ASP.NET请求上下文。
ASP.NET请求上下文pipe理HttpContext.Current
以及一些其他的东西,如文化和安全。 UI上下文都与单个线程(UI线程)紧密关联,但是ASP.NET请求上下文不绑定到特定的线程。 但是,它一次只允许请求上下文中有一个线程。
解决scheme的另一部分是如何async
和await
工作。 我在我的博客上描述了他们的行为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
),则可以在await
后安全地使用HttpContext.Current
,而不必担心。
我发现很好的文章描述了这个问题: http : //byterot.blogspot.cz/2012/04/aspnet-web-api-series-part-3-async-deep.html?m=1
作者深入研究了如何在WebApi框架中调用ExecuteAsync方法,并得出这样的结论:
只有当您返回任务或任务<T>时,ASP.NET Web API操作(以及所有pipe道方法)才会被asynchronous调用。 这听起来很明显,但没有任何带有Async后缀的pipe道方法将在其自己的线程中运行。 使用毯子asynchronous可能是一个用词不当。 [更新:ASP.NET团队确实已经确认,Async用于表示返回任务的方法,并且可以asynchronous运行但不必]
我从文章中了解到,Action方法是同步调用的,但它是调用者的决定。
我为此创build了一个小testing应用程序,如下所示:
public class ValuesController : ApiController { public object Get(string clientId, string specialValue) { HttpRequest staticContext = HttpContext.Current.Request; string staticUrl = staticContext.Url.ToString(); HttpRequestMessage dynamicContext = Request; string dynamicUrl = dynamicContext.RequestUri.ToString(); return new {one = staticUrl, two = dynamicUrl}; } }
和一个asynchronous版本返回async Task<object>
我试图用jQuery做一个DOS的攻击,并不能确定任何问题,直到我用await Task.Delay(1).ConfigureAwait(false);
,这显然会失败。
我从文章中得到的是,问题非常复杂,使用asynchronous操作方法时会发生线程切换,所以在操作方法调用的代码的任何地方使用HttpContext.Current并不是一个好主意。 但是,由于控制器是同步创build的,所以在构造函数中使用HttpContext.Current以及在dependency injection中都可以。
当有人对这个问题有另一个解释时,请纠正我,因为这个问题非常复杂,我还没有100%的信服。
diclaimer:
- 我现在忽略自承载Web-Api的问题,IIS,其中HttpContext.Current可能无法正常工作。 我们现在依靠IIS。
我正在使用一个Web API,这是使用asynchronous/等待方法。
也使用
1) HttpContext.Current.Server.MapPath 2) System.Web.HttpContext.Current.Request.ServerVariables
这工作很好,时间很长,突然之间没有代码的变化。
花费很多时间回到以前的旧版本,发现丢失的关键导致这个问题。
< httpRuntime targetFramework="4.5.2" /> under system.web
我在技术上不是专家。 但是我build议在你的webconfiguration文件中添encryption钥,并给它一个GO 。
- 当我有程序集的时候,WebAPI发现了引用错误
- 微软Web Api返回一个文件? 使用byte ?
- ASP.NET Web API应用程序在IIS 7上部署时提供了404
- 点字符“。” 在MVC Web API 2中用于请求如api / people / STAFF.45287
- Asp.NET Web API – 405 – 用于访问此页面的HTTP动词不被允许 – 如何设置处理程序映射
- 在ASP.NET Web API中使用可选参数的属性路由
- CodeDom提供程序types“Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider”找不到
- POSTstring到ASP.NET Web Api应用程序 – 返回null
- ASP.NET Web API身份validation