0

I'm aware that HttpContext property of controller is async-safe. When you call it inside async action, it always returns context of the current action.

But I'm curious how is this achieved?

If I understand correctly, it can't be implemented using thread-local storage technique. Because after await, an async method can resume on another thread from pool. Or, on the other hand, while an async method is "sleeping", the same thread from pool can execute another async method.

gavv
  • 4,649
  • 1
  • 23
  • 40
  • 2
    If you're aware of thread-local storage you should also become aware of [`AsyncLocal`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1?view=net-5.0) – Damien_The_Unbeliever Nov 09 '21 at 09:06
  • @Damien_The_Unbeliever Oh, shame on me, it was pretty obvious to try googling it first... Thanks. – gavv Nov 09 '21 at 09:11

2 Answers2

1

From HttpContext access from a background thread:

HttpContext access from a background thread

HttpContext isn't thread-safe. Reading or writing properties of the HttpContext outside of processing a request can result in a NullReferenceException.

Storing the HttpContext instance and passing it along or using IHttpContextAccessor interface can get you in trouble because of that.

A controller should collect the necessary request information to pass along to other components/services and use the result of that invocation to contribute response.

Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
  • `IHttpContextAccessor` won't cause any troubles as long as you use it as intended, ie to let a service access the HttpContext within the request scope. If you were to pass the context to another thread (or a Task.Run) it might fail though. It should be noted that `IHttpContextAccessor` uses an AsyncLocal to keep this separated per request though so it carries a small performance penalty that is avoidable if the values are passed from the controller instead. – Karl-Johan Sjögren Nov 09 '21 at 10:50
  • Once you need it, you might already be in trouble. – Paulo Morgado Nov 09 '21 at 13:41
  • Well, that's not an answer to the question (maybe it was not very clear though). I was not asking about accessing context from background thread; I was asking about accessing it from async action. It is safe to access context after await and I was curious why. I didn't know about AsyncLocal when I posted the question. – gavv Nov 09 '21 at 17:10
  • 1
    On .NET Framework, the [AspNetSynchronizationContext](https://referencesource.microsoft.com/#System.Web/AspNetSynchronizationContext.cs,9b31a5e94e4b9894) is responsible for setting `HttpContext.Current` to the correct `HttpContext` instance. Beacause ASP.NET Core is free-thread and there's no `SynchronizationContext`, `IHttpContextAccessor` uses `AsyncLocal` to flow the "current" `HttpContext` instance through async calls. That has nothing to do with invoking members of instances of `HttpContext` being safe or not. – Paulo Morgado Nov 10 '21 at 09:34
0

As suggested by @Damien_The_Unbeliever, HttpContext property indeed uses AsyncLocal, as described in this article:

namespace Microsoft.AspNetCore.Http
{
    public class HttpContextAccessor : IHttpContextAccessor
    {
        private static AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>();

        public HttpContext HttpContext
        {
            get
            {
                return _httpContextCurrent.Value;
            }
            set
            {
                _httpContextCurrent.Value = value;
            }
        }
    }
}
gavv
  • 4,649
  • 1
  • 23
  • 40