ActionController.HttpContext 什么时候设置?

When is ActionController.HttpContext set?

我正在尝试实现一个 ASP.NET 核心 MVC 网络应用程序,类似于 Jason Taylor 的 CleanArchitecture design. In the WebUi "layer" I try to implement an abstraction of an IIdentityService in which I want to access the ClaimsPrincipal 与当前 HttpRequest 关联。

在对 github 上的源代码进行一些挖掘之后,我发现 Controller.User 属性 源于 ControllerBase.HttpContext? which is derived from ControllerContext which in turn is derived from ActionContext,其中 HttpContext 属性 定义为

/// <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;
}

我在这里进入了死胡同。我假设 属性 是由一些中间件初始化的(即来自 Microsoft.Identity 的 .AddAuthentication() / .AddAuthorization()),但我想确认这一点,所以我知道如何获得对我服务中的那个对象。

IPrincipal 的其他来源,ClaimsPrincipal 我从中找到

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

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

使用 IHttpContextAccessor here 的文档,但我无法弄清楚 Controller.User 指向的是哪个。

@JHBonarius 在评论中向正确的方向暗示后,我在 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;

        // ...
    } 
}