【问题标题】:AsyncLocal Value is Null after being set from within Application_BeginRequest()从 Application_BeginRequest() 中设置后,AsyncLocal 值为 Null
【发布时间】: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


【解决方案1】:

最接近权威答案的是this comment by David Fowl 在 GitHub 上。

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

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

这正是人们在 ASP.NET 管道事件之间恢复 AsyncLocal 状态或逻辑 CallContext 所需要的。

【讨论】:

    猜你喜欢
    • 2016-06-18
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    相关资源
    最近更新 更多