In the following example, I am setting a value to an AsyncLocal<string>
variable on my HttpApplication
subclass (i.e. Global.asax) from within 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;
}
}
Later on, I will attempt to access the value of this AsyncLocal
variable from within a handler, such as an MVC action method, or even just a plain IHttpHandler
.
If I send a large enough request (e.g. a POST with more than 15KB of data -- the larger the request, the easier it is to observe), there is a very good chance that the value of AsyncLocalState
is NULL when accessed from a handler even though it was set on BeginRequest
.
This is reproducible from a brand-new ASP.NET project without any other libraries/modules/handlers loaded.
Is this a bug? Or maybe I'm doing something wrong? Or is ASP.NET just too unstable for this?
Addition note: the exact same behavior is observed if I instead use CallContext.LogicalGetData
/CallContext.LogicalSetData
.
Platform: ASP.NET, .NET 4.6.2, on Windows 7
Update: After trying to dig around, I've found a lot of references to, but nothing authoritatively saying that the ExecutionContext
does not flow between ASP.NET pipeline events (except when it does?). And both AsyncLocal
and the logical call context are based on the ExecutionContext
.
The closest thing to an authoritative answer is this comment by David Fowl on GitHub.
The ExecutionContext
does not flow between ASP.NET pipeline events if these events do not execute synchronously. Therefore, don't use AsyncLocal
or the logical CallContext
to persist state; use HttpContext.Items
.
Update: .NET 4.7.1 adds a new callback method, HttpApplication.OnExecuteRequestStep
, which per documentation "provides extensibility to the ASP.NET pipeline to make it easy for developers to implement features in ambient context scenarios and build libraries that care about ASP.NET execution flow (for example, tracing, profiling, diagnostics, and transactions)."
This is precisely what someone would need in order to restore the AsyncLocal
state or the logical CallContext
between ASP.NET pipeline events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With