Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using HttpContext in Async Task

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.

like image 263
Marco Avatar asked Dec 06 '12 16:12

Marco


People also ask

Is HttpContext current thread safe?

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.

Why is HttpContext current null after 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.

What is the use of HttpContext?

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.


2 Answers

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);
}
like image 123
Stephen Cleary Avatar answered Oct 11 '22 11:10

Stephen Cleary


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 awaited). If you end up doing this then you can't do what I suggested in my previous paragraph.

like image 26
Servy Avatar answered Oct 11 '22 10:10

Servy