【发布时间】:2017-04-13 11:48:12
【问题描述】:
在以下示例中,我在Application_BeginRequest() 中为我的HttpApplication 子类(即Global.asax)上的AsyncLocal<string> 变量设置一个值:
public class Global : System.Web.HttpApplication
{
public static AsyncLocal<string> AsyncLocalState = new AsyncLocal<string>();
protected void Application_BeginRequest(object sender, EventArgs e)
{
AsyncLocalState.Value = HttpContext.Current.Request.Path;
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
var path = AsyncLocalState.Value;
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var path = AsyncLocalState.Value;
}
}
稍后,我将尝试从处理程序中访问这个AsyncLocal 变量的值,例如MVC 操作方法,甚至只是一个普通的IHttpHandler。
如果我发送了一个足够大的请求(例如,一个包含超过 15KB 数据的 POST——请求越大,越容易观察),AsyncLocalState 的值很有可能为 NULL当从处理程序访问时即使它设置在BeginRequest。
这可以在没有加载任何其他库/模块/处理程序的全新 ASP.NET 项目中重现。
这是一个错误吗?或者也许我做错了什么?还是 ASP.NET 太不稳定了?
补充说明:如果我改用CallContext.LogicalGetData/CallContext.LogicalSetData,则会观察到完全相同的行为。
平台:ASP.NET、.NET 4.6.2,在 Windows 7 上
更新:在尝试挖掘之后,我发现了很多关于 ExecutionContext 在 ASP 之间流动的引用,但没有任何权威性的说法。 NET 管道事件(除非它发生?)。并且AsyncLocal 和逻辑调用上下文都是基于ExecutionContext。
【问题讨论】:
-
你确定/你能检查
BeginRequest处理程序和后面的方法实际上都是in the same async context吗? -
@GSerg 我不确定如何检查。我将
ValueChangedHandler连接到AsyncLocal,并且在最初设置后它不会被调用。如此依赖于请求的大小也很奇怪——小请求始终“有效”,而大请求却始终“有效”。 -
您通过确保
SynchronizationContext.Current从事件处理程序和方法返回相同的对象来检查。ValueChangedHandler不应触发,因为值不会改变,只是无法从不同的上下文中看到,例如无法从不同的线程中看到ThreadLocal值。 -
小请求通过似乎也不是很奇怪;这通常表示竞争条件。小请求和大请求都不能可靠地工作,但小请求很可能有时间通过。
-
@GSerg 关于请求大小;你对时间的事情有所了解。如果我在设置
AsyncLocal值后闯入BeginRequest并暂停片刻(甚至只是Thread.Sleep(2000)),那么它会更频繁地工作。
标签: asp.net .net asp.net-mvc asynchronous