Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpContext.Current.Items after an Async operation

Tags:

Consider the following ASP.NET Web API Delegating Handler:

public class MyHandler : DelegatingHandler {     protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)     {         var guid = Guid.NewGuid();         HttpContext.Current.Items["foo"] = guid;          // An Async operation         var result = await base.SendAsync(request, cancellationToken);          //All code from this point is not gauranteed to run on the same thread that started the handler          var restoredGuid = (Guid)HttpContext.Current.Items["foo"];          //Is this gauranteed to be true         var areTheSame = guid == restoredGuid;          return result;     } } 

The above example is in a delegating handler, the same problem I am trying to fix applies in Controllers, Business Objects, etc.

I am ultimately trying to provide some simple in-memory shared state between various objects per HTTP Request

As I understand it during Async operations the ASP.NET thread originally running the operation is returned to the thread pool and a different thread may be used to finish the request after the Async operation has completed.

Does this affect the HttpContext.Current.Items collection? Is an item that was in the Items collection guaranteed to be there when the Request resumes?

  1. I'm aware that using HttpContext.Current is often frowned upon by the wider community these days for reasons I completely agree with... I'm just helping someone out of a jam.

  2. Storing this data in the Request.Items collection is not suitable to solve this problem as my colleague requires a static due to some poor design decisions.

Many Thanks

like image 582
Gavin Osborn Avatar asked Aug 27 '13 07:08

Gavin Osborn


People also ask

Why is HttpContext current null after await?

Current as a thread-static variable will no longer resolve to the appropriate value. Now, based on the synchronization context, it could actually be forced to go back to the same thread after the await but I'm not doing anything fancy in my test. This is just a plain, naive use of await .

When should I use HttpContext items?

Similarly, you use HTTPContext Items collection when you are sharing the same information across the different instance based on the user request and that request could be changed for a different request.

Is HttpContext current items thread safe?

The HttpContext is NOT thread safe, accessing it from multiple threads can result in exceptions, data corruption and generally unpredictable results.

What is HttpContext item?

An HttpContext object will encapsulate specific details of a single HTTP request. Properties of this class include the Request object, the Response object, the Session object, and an AllErrors property which keeps an array of Exception objects accrued during the current request.


1 Answers

As I understand it during Async operations the ASP.NET thread originally running the operation is returned to the thread pool and a different thread may be used to finish the request after the Async operation has completed.

That is correct. But let's talk about async on ASP.NET for just a minute.

async requires .NET 4.5. Furthermore, ASP.NET 4.5 introduces a "quirks mode" on the server side, and you have to turn the SynchronizationContext quirk off. You can do this by either setting httpRuntime.targetFramework to 4.5 or using an appSettings with aspnet:UseTaskFriendlySynchronizationContext value of true.

If your web.config does not have one of those entries, then the behavior of async is undefined. See this post for more details. I recommend using the targetFramework setting and fixing any problems that come up.

Does this affect the HttpContext.Current.Items collection? Is an item that was in the Items collection guaranteed to be there when the Request resumes?

The AspNetSynchronizationContext preserves the current request context across await points. This includes HttpContext.Current (which includes Items, User, etc).

Another possibility is CallContext.Logical[Get|Set]Data, which also flows across await points. This is useful if you don't want a code dependency on HttpContext, but has slightly more overhead.

I gave a talk at ThatConference a couple weeks ago on async on the server side; you may find the slides helpful, particularly the ones dealing with Context and Thread-Local State.

like image 96
Stephen Cleary Avatar answered Sep 19 '22 06:09

Stephen Cleary