Search code examples
asp.net-coreasp.net-core-mvcasp.net-core-identity

When is ActionController.HttpContext set?


I am trying to implement an ASP.NET Core MVC web app similar to Jason Taylor's CleanArchitecture design. In the WebUi "layer" I try to implement an abstraction of an IIdentityService in which I want to access the ClaimsPrincipal associated with the current HttpRequest.

After some digging through the source code on github, I found that the Controller.User property stems from ControllerBase.HttpContext? which is derived from ControllerContext which in turn is derived from ActionContext in which the HttpContext property is defined as

/// <summary>
/// Gets or sets the <see cref="Http.HttpContext"/> for the current request.
/// </summary>
/// <remarks>
/// The property setter is provided for unit test purposes only.
/// </remarks>
public HttpContext HttpContext
{
    get; set;
}

Here I am hitting a dead end. I assume the property is initialised by some middleware (ie. .AddAuthentication() / .AddAuthorization() from Microsoft.Identity), but I would like to confirm that, so I know how to get a reference to that object in my service.

Other sources of IPrincipals, from which ClaimsPrincipal I have found are

System.Web.HttpContext.Current.User
ClaimsPrincipal.Current
Thread.CurrentPrincipal

IHttpContextAccessor _httpContextAccessor;
var principal = _httpContextAccessor.HttpContext?.User;

with the documentation for IHttpContextAccessor here, but I cannot figure out which is the one Controller.User is pointing to.


Solution

  • After being hinted in the right direction by @JHBonarius in the comments, I found a documented case in the official documentation

    Use HttpContext from custom components

    For other framework and custom components that require access to HttpContext, the recommended approach is to register a dependency using the built-in Dependency Injection (DI) container. The DI container supplies the IHttpContextAccessor to any classes that declare it as a dependency in their constructors:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddControllersWithViews();
    builder.Services.AddHttpContextAccessor();
    builder.Services.AddTransient<IUserRepository, UserRepository>();
    
    In the following example:

    UserRepository declares its dependency on IHttpContextAccessor. The dependency is supplied when DI resolves the dependency chain and creates an instance of UserRepository.

    public class UserRepository : IUserRepository {
        private readonly IHttpContextAccessor _httpContextAccessor;
    
        public UserRepository(IHttpContextAccessor httpContextAccessor) =>
            _httpContextAccessor = httpContextAccessor;
    
        public void LogCurrentUser()
        {
            var username = _httpContextAccessor.HttpContext.User.Identity.Name;
    
            // ...
        } 
    }