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

.NET Core 6 WebAPI:Program.cs读取请求头及按租户ID配置数据库连接

.NET Core 6 WebAPI 两个需求实现方案

1. 在Program.cs中读取请求头信息

Program.cs是应用的启动配置入口,启动阶段无法直接获取请求头(此时还没有HTTP请求进入)。如果要在请求处理流程中读取请求头,可以通过注册中间件的方式在Program.cs中实现:

var builder = WebApplication.CreateBuilder(args);

// 注册基础服务
builder.Services.AddControllers();
// 注册HttpContext访问器,供后续服务读取请求上下文
builder.Services.AddHttpContextAccessor();

var app = builder.Build();

// 配置中间件,在请求管道中读取请求头
app.Use(async (context, next) =>
{
    // 读取指定请求头,例如tenant-id
    if (context.Request.Headers.TryGetValue("tenant-id", out var tenantId))
    {
        // 将租户ID存入HttpContext.Items,供后续服务/中间件使用
        context.Items["TenantId"] = tenantId.ToString();
        // 调试场景下可直接输出
        Console.WriteLine($"当前请求租户ID: {tenantId}");
    }

    // 执行后续中间件
    await next();
});

app.UseAuthorization();
app.MapControllers();

app.Run();

如果需要在业务服务中读取请求头,可通过注入IHttpContextAccessor实现:

public class TenantService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

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

    public string GetCurrentTenantId()
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext == null) return string.Empty;
        
        httpContext.Request.Headers.TryGetValue("tenant-id", out var tenantId);
        return tenantId.ToString();
    }
}

2. 根据租户ID动态配置数据库连接字符串

方案一:在DbContext中动态切换连接

首先在appsettings.json中配置多租户连接字符串:

"ConnectionStrings": {
  "Tenant001": "Server=localhost;Database=Tenant001;Trusted_Connection=True;",
  "Tenant002": "Server=localhost;Database=Tenant002;Trusted_Connection=True;",
  "Default": "Server=localhost;Database=DefaultTenant;Trusted_Connection=True;"
}

自定义DbContext,通过IHttpContextAccessor获取租户ID,动态设置连接字符串:

public class AppDbContext : DbContext
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IConfiguration _configuration;

    public AppDbContext(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
    {
        _httpContextAccessor = httpContextAccessor;
        _configuration = configuration;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // 优先从HttpContext.Items取租户ID(中间件已存入),其次直接读请求头
        var tenantId = _httpContextAccessor.HttpContext?.Items["TenantId"]?.ToString() 
                       ?? _httpContextAccessor.HttpContext?.Request.Headers["tenant-id"].ToString();
        
        // 根据租户ID匹配连接字符串,无匹配则用默认
        var connectionString = _configuration.GetConnectionString(tenantId) 
                               ?? _configuration.GetConnectionString("Default");

        optionsBuilder.UseSqlServer(connectionString);
    }

    // 定义实体DbSet
    public DbSet<User> Users { get; set; }
}

在Program.cs中注册DbContext:

builder.Services.AddDbContext<AppDbContext>();

方案二:DbContext工厂模式(高并发场景推荐)

如果需要更灵活的DbContext实例控制,可使用IDbContextFactory<T>:

public class AppDbContextFactory : IDbContextFactory<AppDbContext>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IConfiguration _configuration;

    public AppDbContextFactory(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
    {
        _httpContextAccessor = httpContextAccessor;
        _configuration = configuration;
    }

    public AppDbContext CreateDbContext()
    {
        var tenantId = _httpContextAccessor.HttpContext?.Request.Headers["tenant-id"].ToString();
        var connectionString = _configuration.GetConnectionString(tenantId) ?? _configuration.GetConnectionString("Default");

        var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
        optionsBuilder.UseSqlServer(connectionString);

        return new AppDbContext(optionsBuilder.Options);
    }
}

在Program.cs中注册工厂:

builder.Services.AddDbContextFactory<AppDbContext, AppDbContextFactory>();

在控制器中使用:

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IDbContextFactory<AppDbContext> _dbContextFactory;

    public UsersController(IDbContextFactory<AppDbContext> dbContextFactory)
    {
        _dbContextFactory = dbContextFactory;
    }

    [HttpGet]
    public async Task<IActionResult> GetUsers()
    {
        using var dbContext = _dbContextFactory.CreateDbContext();
        var users = await dbContext.Users.ToListAsync();
        return Ok(users);
    }
}

关键注意事项

  • 统一请求头参数名(例如tenant-id),HTTP头不区分大小写,但代码中尽量保持一致。
  • 必须处理租户ID不存在的情况,配置默认连接字符串避免数据库连接失败。
  • 生产环境建议增加租户ID合法性校验,防止非法请求访问未授权数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:21:01