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

如何通过自定义IApplicationModelProvider注册带多段路由的泛型控制器?

自定义IApplicationModelProvider注册多段路由的泛型控制器

核心思路

通过实现IApplicationModelProvider动态生成泛型控制器的具体实例模型,将自定义的多段路由前缀绑定到对应实体类型的泛型控制器上,同时让ASP.NET的默认模型处理逻辑自动识别控制器的Action、属性、过滤器等。

步骤1:定义泛型控制器基类

先编写包含通用业务逻辑的泛型控制器,确保Action、过滤器等特性标记正确:

[ApiController]
public class GenericController<T> : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok($"返回所有{typeof(T).Name}数据");
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        return Ok($"返回ID为{id}的{typeof(T).Name}数据");
    }

    [HttpPost]
    [Authorize]
    public IActionResult Create([FromBody] T model)
    {
        return CreatedAtAction(nameof(GetById), new { id = 1 }, model);
    }
}

步骤2:实现自定义IApplicationModelProvider

该类负责动态注册泛型控制器实例,并绑定多段路由:

using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Reflection;

public class GenericControllerModelProvider : IApplicationModelProvider
{
    // 设置优先级低于默认Provider(默认Order为0),确保默认逻辑能处理我们添加的控制器
    public int Order => -1000;

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        // 配置实体类型与对应路由段的映射
        var controllerMappings = new Dictionary<Type, string[]>
        {
            { typeof(Person), new[] { "Person" } },
            { typeof(Employee), new[] { "hr", "Employee" } },
            { typeof(Department), new[] { "company", "admin", "Department" } }
            // 可扩展更多实体和多段路由
        };

        foreach (var mapping in controllerMappings)
        {
            var entityType = mapping.Key;
            var routeSegments = mapping.Value;
            // 创建泛型控制器的具体类型
            var genericControllerType = typeof(GenericController<>).MakeGenericType(entityType);
            var controllerTypeInfo = genericControllerType.GetTypeInfo();

            // 构建控制器模型
            var controllerModel = new ControllerModel(controllerTypeInfo, Array.Empty<object>());
            // 设置控制器名称(用于路由匹配)
            controllerModel.ControllerName = routeSegments.Last();

            // 添加多段路由前缀
            var routeTemplate = string.Join("/", routeSegments);
            controllerModel.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(routeTemplate))
            });

            // 将控制器模型加入应用模型,后续默认Provider会自动解析Action、过滤器、属性等
            context.Result.Controllers.Add(controllerModel);
        }
    }

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
        // 可在此对已生成的模型做后续调整(如修改路由约束、添加全局过滤器等)
    }
}

步骤3:注册自定义Provider

在Program.cs中将自定义Provider添加到服务集合:

var builder = WebApplication.CreateBuilder(args);

// 添加控制器服务,并注册自定义模型提供者
builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new GenericControllerModelProvider());
});

var app = builder.Build();

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

app.Run();

关键注意事项

  • 泛型控制器基类上的特性(如[ApiController]、[Authorize])会被自动继承,默认模型处理逻辑会识别并应用这些特性的行为。
  • 路由段的最后一段需与控制器名称一致,确保ASP.NET路由系统能正确匹配到对应的控制器实例。
  • 如果需要自定义路由约束或额外路由值,可在SelectorModel中扩展RouteValueDictionary或添加RouteConstraintModel。

内容的提问来源于stack exchange,提问作者Goran Petrović

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:52:19