I have the following mvc action.
public async Task<JsonResult> DoSomeLongRunningOperation()
{
return await Task.Run(() =>
{
//Do a lot of long running stuff
//The underlying framework uses the HttpContext.Current.User.Identity.Name so the user is passed on the messagebus.
}
}
In the task the HttpContext gets null. We did a lot of tricking, but nothing assures us of the HttpContext being available always in our new thread.
Is there a solution to use HttpContext within out async tasks?
In our IocContainer we have registered the following object which passes the username to the framework.
public class HttpContextUserIdentityName : ICredentials
{
public string Name
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
This code is called in a lot of places before persisting to the database.
We need either another way of getting the username of the user initiated the webrequest or fix the issue with the HttpContext being null.
Because the persisting to the database happens in the Task I can't access the HttpContext before entering the task.
I also can't think of a safe way to temporary persist the username so I can implement another ICredentials service object.
HttpContext access from a background threadHttpContext isn't thread-safe. Reading or writing properties of the HttpContext outside of processing a request can result in a NullReferenceException.
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.
What is HttpContext? It holds the current information about the Http request. It contains the information like authorization, authentication, request, response, session, items, users, formOptions, etc. Every HTTP request creates a new object of HttpContext with current information.
You almost never want to use Task.Run
in an ASP.NET method.
I think the cleanest solution (but the most work) is to implement async
-compatible interfaces at your other layers:
public async Task<JsonResult> DoSomeLongRunningOperation()
{
//Do a lot of long running stuff
var intermediateResult = await DoLongRunningStuff();
return await DetermineFinalResult(intermediateResult);
}
You should get whatever information you need from the current context before you start the new thread. In this case, add something like:
string username = HttpContext.Current.User.Username;
before Task.Run
and then use that inside of the other thread.
On a side note, as it stands, there's no reason to await
the task. You can just return the task directly and not mark the method as Async
.
If you need to access the Response
object, which will presumably to utilize the results of the long running operation and thus can't be before Task.Run
you should do so after the Task.Run
(but ensure that the task is await
ed). If you end up doing this then you can't do what I suggested in my previous paragraph.
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