Async Await looses HttpContext

Posts   
 
    
Ries
User
Posts: 46
Joined: 23-Aug-2006
# Posted on: 27-Sep-2016 23:17:53   

I have some code that runs in ASP.NET, and uses async await.

The code relies on the HttpContext.Current to store logical-thread context data, such as the current user ID, and the data access adapter and outer transaction used during the logical thread.

I have setup LLBLGen entity Auditing using a custom Auditor class, which is used to clear a cache upon changes to entities.

During an awaited call to SaveEntityAsync, an Auditor is called as expected.

However, the code in the auditor has lost the HttpContext; HttpContext.Current == null.

This breaks the access to the data for the logical thread.

I traced this down to the use of ConfigureAwait(false) in LLBLGen.

Would you consider a static configuration setting in LLLBLGen to specify the true/false value for ConfigureAwait? If I can specify 'true', I'm happy.

Thanks, Ries

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 28-Sep-2016 08:08:22   

Where exactly do you need the user variable? What LLBLGen version are you using? Maybe this link is useful in this case: http://stackoverflow.com/questions/28427675/correct-way-to-use-httpcontext-current-user-with-async-await

David Elizondo | LLBLGen Support Team
Ries
User
Posts: 46
Joined: 23-Aug-2006
# Posted on: 28-Sep-2016 08:23:05   

Hi Daelmo,

I am using 5.0.6 and reviewed the sources.

I need my context "all the time" as the entire request is one logical thread.

Currently after my first call into LLBLGen, the logical thread context is "lost" as pointed out in the Stack Overflow article that you reference. Pls look at the fragment where it states "In this case, the problem is obvious."

await entity.SaveEntityAsync(); Here: Assert.IsTrue(HttpContext.Current == null); // BUG

LLBLGen is written assuming that itself will never need any thread-context, as per the manual. See "Performance related choices" in http://www.llblgen.com/documentation/4.1/LLBLGen%20Pro%20RTF/using%20the%20generated%20code/Async/gencode_async_gettingstarted.htm

However that design decision did not take into consideration that the caller of the async "library method" will continue on the "context unaware" thread-pool that LLBLGen spawned after its call to await. It's not about if LLBLGen needs to maintain access to HttpContext.Current, but if the caller needs it.

Thx

Ries

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 28-Sep-2016 09:35:15   

ConfigureAwait is essential in our code and the problem lies within ASP.NET and the usage of a static resource that's thread bound like HttpContext. It's needed for deadlock prevention and all library code that is used as async code needs to call this method. This won't change.

It's been asked before and I'll quote the replies here which will help you work around this issue with asp.net. (as it's a helpdesk thread)

The problem is that ConfigureAwait(false) is required to avoid deadlocks: inside our library all calls in any callchain inside it have to have ConfigureAwait(false) on them, otherwise it runs the risk of deadlocks. It's key for library code to use ConfigureAwait(false), wherever it can (and does, every library does this in async methods)

Hopefully this helps, as I can understand this is a tricky situation to solve. I have the feeling setting aspnet:UseTaskFriendlySynchronizationContext to true in appsettings might be what makes this work.

Exactly the same problem: https://github.com/xbehave/xbehave.net/issues/286#issuecomment-182256532

Reasoning why you shouldn't do this: https://social.msdn.microsoft.com/Forums/en-US/ea21ca57-5340-439c-8ee9-f0185b5787a1/callcontext-what-are-the-recommendations-for-using-this-going-forwards?forum=async

And MS has fixed this issue: https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/2698599-add-an-async-compatible-logical-call-context

so you should use: http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html

Or use another form of static data storage that's available when the async code is called. There's no other way, unfortunately.

Frans Bouma | Lead developer LLBLGen Pro
Ries
User
Posts: 46
Joined: 23-Aug-2006
# Posted on: 28-Sep-2016 12:44:32   

Thanks Frans for the tips

I am on .net 4.5.2, as per this article and my testing, aspnet:UseTaskFriendlySynchronizationContext makes no difference because of that.

http://stackoverflow.com/questions/20478381/asp-net-vs-mvc-vs-webapi-and-usetaskfriendlysynchronizationcontext

When running in testers or from a console app, my code already relies on LogicalSetData. So it looks as if after the first await, I just have to live with the ASP.NET Context being "off limits", and store any context using LogicalSetData. I relied on the HttpContext.Current.Items instead when in ASP.NET. I play around a bit to see if I refactor for using LogicalSetData inside ASP.NET for everything.

Ries

Ries
User
Posts: 46
Joined: 23-Aug-2006
# Posted on: 28-Sep-2016 13:43:44   

Guys,

Storing my logical thread (request) context items using SetLogicalData seems to work fine, incombination with async methods to LLBLGen.

I used this approach:

http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html

Thx Ries

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 28-Sep-2016 14:57:57   

great that it solved your problem and thanks for the feedback! simple_smile

Frans Bouma | Lead developer LLBLGen Pro