TL;DR
On ASP.NET Core, the access to the request context can be done via the new IHttpContextAccessor
interface, which provides a HttpContext
property with this information. The IHttpContextAccessor
is obtained via dependency injection or directly from the service locator. However, it requires an explicit service collection registration, mapping the IHttpContextInterface
to the HttpContextAccessor
concrete class, with singleton scope.
Not so short version
System.Web
On classical ASP.NET, the current HTTP context, containing both request and response information, can be accessed anywhere via the omnipresent System.Web.HttpContext.Current
static property. Internally, this property uses information stored in the CallContext
object representing the current call flow. This CallContext
is preserved even when the same flow crosses multiple threads, so it can handle async
methods.
ASP.NET Web API
On ASP.NET Web API, obtaining the current HTTP context without having to flow it explicitly on every call is typically achieved with the help of the dependency injection container.
For instance, Autofac provides the RegisterHttpRequestMessage
extension method on the ContainerBuilder
, which allows classes to have HttpRequestMessage
constructor dependencies.
This extension method configures a delegating handler that registers the input HttpRequestMessage
instance into the current lifetime scope.
ASP.NET Core
ASP.NET Core uses a different approach. The access to the current context is provided via a IHttpContextAccessor
service, containing a single HttpContext
property with both a getter and a setter. So, instead of directly injecting the context, the solution is based on injecting an accessor to the context.
This apparently superfluous indirection provides one benefit: the accessor can have singleton scope, meaning that it can be injected into singleton components.
Notice that injecting a per HTTP request dependency, such as the request message, directly into another component is only possible if the component has the same lifetime scope.
In the current ASP.NET Core 1.0.0 implementation, the IHttpContextAccessor
service is implemented by the HttpContextAccessor
concrete class and must be configured as a singleton.
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); }
Notice that this registration is not done by default and must be explicitly performed. If not, any IHttpContextAccessor
dependency will result in an activation exception.
On the other hand, no additional configuration is need to capture the context at the beginning of each request, because this is automatically done.
The following implementation details shed some light on this behavior:
- Each time a new request starts to be handled, a common
IHttpContextFactory
reference is used to create theHttpContext
. This common reference is obtained by theWebHost
during startup and used for all requests. - The used
HttpContextFactory
concrete implementation is initialized with an optionalIHttpContextAccessor
implementation. When available, this accessor is assigned with each created context. This means that if any accessor is registered on the services, then it will automatically be used to set all created contexts. -
How can the same accessor instance hold different contexts, one for each call flow? The answer lies in the
HttpContextAccessor
concrete implementation and its use ofAsyncLocal
to store the context separately for each logical call flow. It is this characteristics that allows a singleton scoped accessor to provide request scoped contexts.
To conclude:
-
Everywhere the HTTP context is needed, declare an
IHttpContextAccessor
dependency and use it to fetch the context. -
Don’t forget to explicitly register the
IHttpContextAccessor
interface on the service collection, mapping it to the concreteHttpContextAccessor
type. -
Also, don’t forget to make this registration with singleton scope.
Pingback: ASP.NET Core Dependency Injection « Thuru's Blog