How to inject HttpContext or ActionContext ?
asp.net-core

How to inject HttpContext or ActionContext ?

Few tools from the ASP.NET Core framework may be quite useful, but you should use the proper way to access them. This way is not always obvious, and knowing about it makes all the difference.This post explains how to allow injection of HttpContext and ActionContext in another injected class.

HttpContext and ActionContext are two classes that describe how the framework understands the current request, and how it is going to handle it.

HttpContext may bring you information about the Request (path, headers, cookies, etc), the user identity, the current set of services, etc. Microsoft website defines it as 'Encapsulates all HTTP-specific information about an individual HTTP request.'

Although it is already registered on several base MVC classes and accessible via Context or HttpContext property, in a custom class, you usually cannot just inject the HttpContext class. To inject the HttpContext or ActionContext classes, instead the .Net team has set up accessors dedicated to that requirement: IHttpContextAccessor and IActionContextAccessor.

A reason behind? Probably that you would be able to access these context into singleton classes, such as middlewares.

IHttpContextAccessor and IActionContextAccessor are not registered by default, and should be registered as singleton. Therefore

  • if you want to properly inject IActionContextAccessor, you need to call at startup:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
  • regarding the HttpContextAccessor , if you want to properly inject IHttpContextAccessor , the team has added an extension method that you should to call during the initialization:
using Microsoft.Extensions.DependencyInjection;

services.AddHttpContextAccessor();

And then you are properly set to access HttpContext or ActionContext.

Example of use

IHttpContextAccessor: implementing a base Controller class

In a project, we often have code that may be shared among our controllers.

Implementing a base class for our project controllers may be a good way to share some common behaviors and add some shortcuts which may be useful in many methods in different controllers. The extra bonus would be that it simplifies the controller code and gives more visibility to the actual core business code.

public class BaseController : Controller // extending Controller is optional
{
    protected Service1 CommonService1 { get; }
    protected Service2 CommonService2 { get; }
    
    public BaseController(CommonService1 commonService1
                          , CommonService2 commonService2)
    {
        this.CommonService1 = commonService1;
        this.CommonService2 = commonService2;
    }
}

However this base class may require several services which would make the constructor of the implementation classes look pretty ugly with a large amount of dependencies. This would go against our will of simplification of the end-user controllers.

public class MyController : BaseController
{
    protected Service3 CommonService3 { get; }
    protected Service4 CommonService4 { get; }
    
    public MyController(CommonService1 commonService1
                          , CommonService2 commonService2
                          , CommonService3 commonService3
                          , CommonService4 commonService4) 
    				: base(CommonService1 commonService1
                          , CommonService2 commonService2)
    {
        this.CommonService3 = commonService3;
        this.CommonService4 = commonService4;
    }
    private void Method1()
    {
        CommonService1.Call1();
    }
}

One possibility would be to take advantage of the Controller.HttpContext.RequestServices to request services silently in the constructor, however you may notice that the HttpContext is null in the constructor and is populated after.

So we can make use of IHttpContextAccessor to access the Services in the constructor, it allows having a single dependency to pass to the base controller :

public class BaseController : Controller // extending Controller is optional
{
    private IServiceProvider _Services;
    protected Service1 CommonService1 { get; }
    protected Service2 CommonService2 { get; }
    
    public BaseController(IHttpContextAccessor httpContextAccessor)
    {
        this._Services = httpContextAccessor.HttpContext.RequestServices;
        
        this.CommonService1 = services.GetRequiredService<Service1>();
        this.CommonService2 = services.GetRequiredService<Service2>();
    }
}

Note that this does not exactly follow the Explicit Dependencies Principle, but you may notice the GetRequiredService which will throw a comprehensible exception if the service is not well registered. This will avoid silent fails by assigning a null value to the variables and later surprises.

From there you can implement any controller, by passing a single dependency to the base class:

public class MyController : BaseController
{
    public MyController(IHttpContextAccessor httpContextAccessor) 
    				: base(httpContextAccessor)
    {

    }
    private void Method1()
    {
        CommonService1.Call1();
    }
}

We have seen in this post how to inject HttpContext and ActionContext in a custom class, done by registering and injecting their respective accessors.


Send
Please sign-in to comment
.X0001-01-01_00-00