从Application_BeginRequest()中设置后,AsyncLocal值为Null

Jos*_*gle 5 .net asp.net asp.net-mvc asynchronous

在下面的示例中,我从内部为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

稍后,我将尝试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.

Jos*_*gle 6

最接近的一个权威的答案是这样评论的大卫鸡在GitHub上。

在ExecutionContext 不流动,如果这些事件不会同步执行ASP.NET管道事件之间。因此,不要使用AsyncLocal或逻辑CallContext上保持状态;使用HttpContext.Items。

更新:.NET 4.7.1添加了一个新的回调方法,HttpApplication.OnExecuteRequestStep该回调方法根据文档“ 提供了对ASP.NET管道的可扩展性,使开发人员可以轻松地在环境上下文方案中实现功能并构建关心ASP.NET执行流程的库。 (例如,跟踪,分析,诊断,和交易)。 “

这正是某人为了还原ASP.NET管道事件之间的AsyncLocal状态或逻辑所需要的CallContext。