You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 6 WebAPI如何全局复用请求头初始化的UserDetails对象

解决方案:在.NET Core 6 WebAPI中复用请求级别的UserDetails实例

问题分析

你需要实现的是请求级别的UserDetails复用,而非全局单例(全局单例会导致多请求间数据混乱)。之前的代码存在几个核心问题:

  • 中间件内新建了独立的UserDetails实例,未关联到DI容器的Scoped实例
  • Program.cs中错误地获取中间件实例并调用InvokeAsync,不符合中间件的正确使用逻辑

正确实现步骤

1. 保留UserDetails类

public class UserDetails
{
    public int UserId { get; set; }
    public string UserName { get; set; }
}

2. 修改中间件:从DI获取Scoped实例并赋值

中间件的核心逻辑是拿到当前请求的Scoped UserDetails实例,从HttpContext读取请求头填充属性:

public class UserDetailsMiddleware
{
    private readonly RequestDelegate _next;

    public UserDetailsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext, UserDetails userDetails)
    {
        // 安全解析UserId(避免非数字格式的请求头导致异常)
        if (int.TryParse(httpContext.Request.Headers["userid"], out var userId))
        {
            userDetails.UserId = userId;
        }
        userDetails.UserName = httpContext.Request.Headers["username"];

        // 继续执行后续中间件
        await _next(httpContext);
    }
}

3. 正确配置Program.cs

  • 将UserDetails注册为Scoped(每个请求生成一个实例,保证请求内复用、请求间隔离)
  • 按顺序注册中间件(需放在业务中间件之前)
var builder = WebApplication.CreateBuilder(args);

// 注册Scoped生命周期的UserDetails
builder.Services.AddScoped<UserDetails>();
// 注册你的其他业务服务
builder.Services.AddScoped<IMyService, MyService>();
builder.Services.AddScoped<IMyGateway, MyGateway>();

var app = builder.Build();

// 注册用户信息中间件(需放在UseRouting、UseEndpoints之前)
app.UseMiddleware<UserDetailsMiddleware>();

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();

4. 在业务服务中直接注入使用

由于UserDetails是Scoped实例,同一个请求内所有注入的UserDetails都是同一个对象,直接使用即可:

public class MyService : IMyService
{
    private readonly IMyGateway _myGateway;
    private readonly UserDetails _userDetails;

    public MyService(IMyGateway myGateway, UserDetails userDetails)
    {
        _myGateway = myGateway;
        _userDetails = userDetails;
    }

    public async Task<string> MyMethod()
    {
        string userId = _userDetails.UserId.ToString();
        // 此处可使用userId调用网关逻辑
        return await _myGateway.GenerateAsync();
    }
}

关键说明

  • Scoped生命周期:每个HTTP请求对应一个UserDetails实例,请求结束后自动销毁,既保证请求内复用,又避免多请求间的数据污染
  • 中间件依赖注入:在InvokeAsync方法中直接注入UserDetails,ASP.NET Core会自动解析当前请求的Scoped实例
  • 类型安全处理:解析UserId时用int.TryParse避免非数字格式请求头引发的异常

内容的提问来源于stack exchange,提问作者WorksOnMyLocal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 06:21:57