'Why is HttpContext.Current null after await?
I have the following test WebAPI code, I don't use WebAPI in production but I made this because of a discussion I had on this question: WebAPI Async question
Anyways, here's the offending WebAPI method:
public async Task<string> Get(int id)
{
var x = HttpContext.Current;
if (x == null)
{
// not thrown
throw new ArgumentException("HttpContext.Current is null");
}
await Task.Run(() => { Task.Delay(500); id = 3; });
x = HttpContext.Current;
if (x == null)
{
// thrown
throw new ArgumentException("HttpContext.Current is null");
}
return "value";
}
I had hereto believed that the second exception is expected because when the await completes, it will likely be on a different thread where HttpContext.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.
In comments in another question I was told that HttpContext.Current should resolve after an await. There's even another comment on this question indicating the same. So what's true? Should it resolve? I think no, but I want an authoritative answer on this because async and await is new enough that I can't find anything definitive.
TL;DR: Is HttpContext.Current potentially null after an await?
Solution 1:[1]
As @StephenCleary correctly pointed out, you need this in your web.config:
<httpRuntime targetFramework="4.5" />
When I was first troubleshooting this, I did a solution-wide search for the above, confirmed it was present in all my web projects and quickly dismissed it as the culprit. Eventually it occurred to me to look at those search results in full context:
<!--
For a description of web.config changes for .NET 4.5 see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.5" />
</system.Web>
-->
Doh.
Lesson: If you upgrade a web project to 4.5, you still need to get that setting in place manually.
Solution 2:[2]
I ran into this issue recently. As Stephen pointed out not setting explicitly the target framework can generate this issue.
In my case, our Web API was migrated to version 4.6.2 but the runtime target framework was never specified in the web config, so basically this was missing inside the <system.web> tag:
If you have doubts about the framework version you are running this may help: Add the following line on any of your Web API methods and set a breakpoint to verify what type is currently loaded at runtime and verify it is not a Legacy implementation:
You should see this (AspNetSynchronizationContext):
Instead of LegazyAspNetSynchronizationContext (Which was what I saw before adding the target framework):
If you go to the source code (https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs) you will see that the Legacy implementation of this interface lacks of asynchronous support.
I spent a lot of time trying to find the source of the issue and Stephen´s response helped a lot. Hope this answer provides some more information about the issue.
Solution 3:[3]
Is my test flawed, or is there some web.config element I'm missing here that would make HttpContext.Current resolve correctly after an await?
Your test is not flawed and HttpContext.Current should not be null after the await because in ASP.NET Web API when you await, this will ensure that the code that follows this await is passed the correct HttpContext that was present before the await.
Solution 4:[4]
I wanted to comment and say that the previous answers hit the nail on the head from a web.config perspective, however, there can be inherited settings from IIS that can override this functionality if you simply use <httpRuntime targetFramework="4.5" />.
What I mean:
The true fix here is this setting:
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
If you don't explicitly include this setting but rely on <httpRuntime targetFramework="4.5" /> to configure this setting - it will be overridden by any settings in IIS.
If you are debugging or logging the type of SynchronizationContext and you find out it's of type Legacy, you may want to check for a setting at the IIS or hosting Site level.
Will yield LegacyAspNetSynchronizationContext:
Web.config:
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="aspnet:UseLegacyEncryption" value="true" />
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.5" />
</system.web>
Will yield AspNetSynchronizationContext (this is what you want):
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
<add key="aspnet:UseLegacyEncryption" value="true" />
<add key="aspnet:UseLegacyMachineKeyEncryption" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.5" />
</system.web>
*Note there is no override setting in IIS here
Solution 5:[5]
I tried all the other answers here and HttpContext.Current was still null.
.net Framework 4.6.1 / MVC
I'm using HttpContext.Current to get the mapped path for an upload to App_Data
This is how I fixed the issue:
I just obtain the current HttpContext.Current in a variable and then reset it after my await calls.
var tempHttpContextCurrent = System.Web.HttpContext.Current;
var report = await reportingUtilities.GetReport(reportId, currentUserRubixId).ConfigureAwait(false);
// reset the HttpContext.Current after the await call.
System.Web.HttpContext.Current = tempHttpContextCurrent;
Solution 6:[6]
In my case the problem was I forget await in the begining of stack, explicity in my constructor action method
NOTE: Using net core 5.0 with IHttpContextAccessor
So the problem was in code...
[HttpPost]
public async Task AnyAction()
{
await service.MethodReturningTask(); //await was not
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Todd Menier |
| Solution 2 | abarrenechea |
| Solution 3 | |
| Solution 4 | |
| Solution 5 | |
| Solution 6 | Juan Pablo |




