我的问题与此有点相关:WebApi equivalent for HttpContext.Items with Dependency Injection。
我们想使用Ninject在WebApi区域中使用HttpContext.Current注入一个类。
我担心的是,这可能是非常危险,因为在WebApi(所有内容?)是异步的。
如果我在这些问题上错了,请纠正我,这是我到目前为止调查的内容:
HttpContext.Current通过Thread获取当前上下文(我直接查看了实现)。
在异步任务中使用HttpContext.Current是不可能的,因为它可以在另一个线程上运行。
WebApi使用IHttpController方法Task<HttpResponseMessage> ExecuteAsync
=&gt;每个请求都是async =&gt;你不能在action方法中使用HttpContext.Current。它甚至可能发生,更多的请求是通过相同的线程在同一个线程上执行的。
为了将带有注入内容的控制器创建到构造函数中,IHttpControllerActivator与 sync 方法IHttpController Create
一起使用。这就是ninject创建Controller及其所有依赖项的地方。
如果我在所有这四点中都是正确的,那么在动作方法或下面任何一层中使用HttpContext.Current是非常危险的,并且会产生意想不到的结果。我看到很多公认的答案正是如此。恕我直言,这可以工作一段时间,但会在负载下失败。
但是当使用DI创建一个Controller及其依赖项时,它是好的,因为它在一个独立的线程上运行。 我可以从构造函数中的HttpContext获取一个值,它会安全吗?。我想知道是否每个请求都在单个线程上创建了Controller,因为这可能会导致重负载下的问题,其中可以使用来自IIS的所有线程。
只是为了解释我为什么要注入HttpContext的东西:
我们想要的解决方案:它们之间的所有层都没有受到影响,我们可以在代码深处的某个地方使用注入的请求(例如,在一些依赖于URL的ConfigurationProvider中)
如果我完全错误或者我的建议是正确的,请告诉我你的意见,因为这个主题似乎非常复杂。 Thx提前!
答案 0 :(得分:96)
HttpContext.Current通过Thread获取当前上下文(我直接查看了实现)。
将HttpContext
应用于线程更为正确;或线程&#34;进入&#34; HttpContext
。
在异步任务中使用HttpContext.Current是不可能的,因为它可以在另一个线程上运行。
完全没有; async
/ await
的默认行为将在任意线程上恢复,但该线程将在恢复async
方法之前进入请求上下文。
关键是SynchronizationContext
。如果您不熟悉,我会MSDN article on the subject。 SynchronizationContext
定义了一个&#34; context&#34;对于一个平台,常见的是UI上下文(WPF,WinPhone,WinForms等),线程池上下文和ASP.NET请求上下文。
ASP.NET请求上下文管理HttpContext.Current
以及文化和安全等其他一些内容。 UI上下文都与单个线程( UI线程)紧密关联,但ASP.NET请求上下文与特定线程无关。但是,它一次只允许请求上下文中的一个线程。
解决方案的另一部分是async
和await
的工作原理。我有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必须更改其SynchronizationContext
以使用async
/ 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
,而无需担心。< / p>
答案 1 :(得分:4)
我正在使用web api,它正在使用async / await方法。
也使用
1) HttpContext.Current.Server.MapPath
2) System.Web.HttpContext.Current.Request.ServerVariables
这项工作正常,因为没有代码更改而突然中断。
通过恢复到以前的旧版本而花费大量时间,发现丢失的密钥会导致问题。
< httpRuntime targetFramework="4.5.2" /> under system.web
我不是技术专家。但我建议将密钥添加到您的网络配置中并为其指定 GO 。
答案 2 :(得分:2)
我发现非常好的文章正好描述了这个问题:http://byterot.blogspot.cz/2012/04/aspnet-web-api-series-part-3-async-deep.html?m=1
作者深入研究了如何在WebApi框架中调用ExecuteAsync方法并得出这样的结论:
仅当您返回任务或任务&lt; T&gt;时,才会异步调用ASP.NET Web API操作(以及所有管道方法)。这可能听起来很明显,但是没有带有Async后缀的管道方法都会在自己的线程中运行。使用毯式异步可能是用词不当。 [更新:ASP.NET团队确实已经确认Async用于表示返回Task的方法,并且可以异步运行但不必运行]
我从文章中了解到,Action方法是同步调用的,但它是调用者的决定。
我为此创建了一个小型测试应用程序,如下所示:
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};
}
}
和一个返回async Task<object>
我试图用jquery对它进行一点DOS攻击,直到我使用await Task.Delay(1).ConfigureAwait(false);
才能确定任何问题,这显然会失败。
我从文章中得到的是,问题非常复杂,并且在使用异步操作方法时可能会发生Thread切换,所以在任何地方使用HttpContext.Current肯定是 NOT 一个好主意从动作方法调用的代码。但是,由于控制器是同步创建的,因此在构造函数中使用HttpContext.Current以及依赖注入也是可以的。
如果有人对此问题有另一种解释,请纠正我,因为这个问题非常复杂,我仍然不是100%确信。
diclaimer: