IHttpContextAccessor.HttpContext.User.Identity 显示 CurrentUserService 服务中的所有空属性

IHttpContextAccessor.HttpContext.User.Identity shows all null properties in CurrentUserService service

我正在尝试使用Jason Taylor's Clean Architecture Template,这个模板使用NSwag自动创建一个TypeScript客户端(Angular),但我不需要创建一个TS客户端,所以我的主要目标就是用Razor Pages代替。我已经能够很好地实现这一点,但是我在 CurrentUserService 遇到问题,每当它被实例化时,它应该在这一行中设置 UserId:

UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);

这是完整的 CurrentUserService:

using CleanREC0.Application.Common.Interfaces;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;

namespace CleanREC0.WebUI.Services
{
    public class CurrentUserService : ICurrentUserService
    {
        public CurrentUserService(IHttpContextAccessor httpContextAccessor)
        {
            UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
        }

        public string UserId { get; }
    }
}

第一次连 HttpContext 都是 null 这很好,因为一切都在初始化,但后续调用总是 return null 在所有 httpContextAccessor.HttpContext.User.Identity 属性上,用户显示 身份 没问题,但它的所有属性和声明都是 null没有结果,即使用户正确登录也是如此。

这是我对模板所做的事情的列表:

这是我的 StartUp class:

public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplication();
            services.AddInfrastructure(Configuration, Environment);    

            services.AddScoped<ICurrentUserService, CurrentUserService>();

            services.AddHttpContextAccessor();
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //I have added this line on as suggested on other post, but made no difference.


            services.AddHealthChecks()
                .AddDbContextCheck<ApplicationDbContext>();

            services.AddRazorPages()
                .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<IApplicationDbContext>());
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseCustomExceptionHandler();
            app.UseHealthChecks("/health");
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
        }
    }

这是从 ConfigureServices 调用的 AddApplication:

public static IServiceCollection AddApplication(this IServiceCollection services)
        {
            services.AddAutoMapper(Assembly.GetExecutingAssembly());
            services.AddMediatR(Assembly.GetExecutingAssembly());
            services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPerformanceBehaviour<,>));
            services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestValidationBehavior<,>));

            return services;
        }

AddInfrastructure 也在那里被调用:

public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration, IWebHostEnvironment environment)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    configuration.GetConnectionString("DefaultConnection"), 
                    b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));

            services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());

            services.AddDefaultIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            if (environment.IsEnvironment("Test"))
            {

            }
            else
            {
                services.AddTransient<IDateTime, DateTimeService>();
                services.AddTransient<IIdentityService, IdentityService>();
                services.AddTransient<ICsvFileBuilder, CsvFileBuilder>();
            }

            services.AddAuthentication();

            return services;
        }

其他一切似乎都正常。在 Razor Page 级别,User 变量及其 Identity 包含所有预期信息和声明。

我确定我遗漏了什么,有人能给我指明正确的方向吗?

LinkedListT 在评论中的 link 让我找到了正确的方向。

link 指向一个解释此问题的答案:

under the ASP.NET MVC framework, the HttpContext (and therefore HttpContext.Session) is not set when the controller class is contructed as you might expect, but it set ("injected") later by the ControllerBuilder class.

我正在使用的模板附带的 CurrentUserService class 试图读取构造函数中的用户声明,因此我将代码移至 属性 的 getter,执行到后面 属性 实际使用时,到那时所有声明和属性都已填充。

我的新 CurrentUserService 看起来像这样:

using CleanREC0.Application.Common.Interfaces;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;

namespace CleanREC0.WebUI.Services
{
    public class CurrentUserService : ICurrentUserService
    {
        private IHttpContextAccessor _httpContextAccessor;

        public CurrentUserService(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public string UserId { get { return _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); }}
    }
}