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

时间:2017-04-13 11:48:13

标签: asp.net .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;
    }
}

稍后,我将尝试从处理程序(例如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

1 个答案:

答案 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所需要的。