在以下示例中,我将AsyncLocal<string>
子类中的HttpApplication
变量(即Global.asax)设置为Application_BeginRequest()
内的值:
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;
}
}
稍后,我将尝试从处理程序(例如MVC操作方法)或甚至只是普通AsyncLocal
中访问此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
。
答案 0 :(得分:4)
与权威答案最接近的是this comment在GitHub上的David Fowl。
如果这些事件不同步执行,则ExecutionContext
不会在ASP.NET管道事件之间流动。因此,请勿使用AsyncLocal
或逻辑CallContext
来保持状态;使用HttpContext.Items
。
更新:.NET 4.7.1添加了一个新的回调方法HttpApplication.OnExecuteRequestStep
,每个文档“为ASP.NET管道提供可扩展性,使开发人员可以轻松实现环境上下文场景中的功能并构建关心ASP.NET执行流程的库(例如,跟踪,分析,诊断和事务)。“
这正是人们在ASP.NET管道事件之间恢复AsyncLocal
状态或逻辑CallContext
所需要的。