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

如何在ASP.NET Core 7中条件化添加指定控制器?

多集群多租户场景下按需发布控制器端点的实现方案

针对你这种同一应用部署在多集群、各集群服务特定租户,需要仅在指定集群发布特定控制器的场景,这里提供几个比路由内判断返回404更简洁的方案:

方案一:基于配置的控制器条件注册(推荐)

这个方案从应用启动阶段就直接过滤掉不需要注册的控制器,端点不会出现在路由表中,Swagger也不会展示,完全符合“不在C1中发布”的需求。

  1. 首先在appsettings.json中配置当前集群服务的租户列表:
{
  "TenantSettings": {
    "ServedTenants": ["T3", "T4"] // C2集群的配置,C1集群则配置为["T1", "T2"]
  }
}
  1. 在Program.cs中读取配置,判断是否注册目标控制器:
var builder = WebApplication.CreateBuilder(args);

// 读取当前集群服务的租户列表
var servedTenants = builder.Configuration.GetSection("TenantSettings:ServedTenants").Get<string[]>();

// 注册控制器,按需包含目标控制器所在程序集
builder.Services.AddControllers()
    .ConfigureApplicationPartManager(apm =>
    {
        // 获取目标控制器所在的程序集部件
        var targetAssemblyPart = apm.ApplicationParts
            .FirstOrDefault(p => p.Name == typeof(TargetController).Assembly.GetName().Name);
        
        if (targetAssemblyPart != null)
        {
            // 仅当当前集群服务T3/T4时保留该部件,否则移除
            var shouldKeep = servedTenants?.Any(t => t is "T3" or "T4") == true;
            if (!shouldKeep)
            {
                apm.ApplicationParts.Remove(targetAssemblyPart);
            }
        }
    });

var app = builder.Build();

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

app.Run();

方案二:自定义特性+全局筛选器

如果需要更灵活的租户匹配规则,或者不想修改程序集注册逻辑,可以用全局筛选器实现控制器级别的访问控制:

  1. 创建一个标记控制器需要特定租户的特性:
[AttributeUsage(AttributeTargets.Class)]
public class RequireTenantsAttribute : Attribute
{
    public string[] AllowedTenants { get; }

    public RequireTenantsAttribute(params string[] allowedTenants)
    {
        AllowedTenants = allowedTenants;
    }
}
  1. 在目标控制器上标记该特性:
[RequireTenants("T3", "T4")]
[ApiController]
[Route("api/[controller]")]
public class TargetController : ControllerBase
{
    // 控制器方法逻辑
}
  1. 实现全局筛选器,检查当前集群是否允许访问该控制器:
public class TenantControllerFilter : IActionFilter
{
    private readonly string[] _servedTenants;

    public TenantControllerFilter(string[] servedTenants)
    {
        _servedTenants = servedTenants ?? Array.Empty<string>();
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        var requireAttr = context.Controller.GetType().GetCustomAttribute<RequireTenantsAttribute>();
        if (requireAttr != null)
        {
            var hasPermission = requireAttr.AllowedTenants.Intersect(_servedTenants).Any();
            if (!hasPermission)
            {
                context.Result = new NotFoundResult();
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext context) { }
}
  1. 在Program.cs中注册筛选器:
var builder = WebApplication.CreateBuilder(args);
var servedTenants = builder.Configuration.GetSection("TenantSettings:ServedTenants").Get<string[]>();

builder.Services.AddControllers(options =>
{
    options.Filters.Add(new TenantControllerFilter(servedTenants));
});

var app = builder.Build();

// 中间件配置...
app.MapControllers();
app.Run();

方案三:端点路由的条件映射

如果只需要控制特定端点的发布,而非整个控制器,可以在端点路由阶段条件注册:

var app = builder.Build();
var servedTenants = app.Configuration.GetSection("TenantSettings:ServedTenants").Get<string[]>();

app.UseHttpsRedirection();
app.UseAuthorization();

// 映射所有常规控制器端点
app.MapControllers();

// 仅当当前集群服务T3/T4时,映射目标控制器的端点
if (servedTenants?.Any(t => t is "T3" or "T4") == true)
{
    app.MapControllerRoute(
        name: "target-controller",
        pattern: "api/target/{action}",
        defaults: new { controller = "Target" });
}

app.Run();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:10:11