ASP.NET Core如何配置Api子文件夹路由分离Api与View控制器
.NET 6 ASP.NET Core Api子目录控制器路由404修复方案
改造背景
针对大体量.NET 6 ASP.NET Core项目做非全量重构的渐进式改造,目标为分离数据逻辑与视图逻辑:
- 将视图控制器中混杂的大量数据端点迁移至独立控制器
- 缩减视图控制器代码体积
- 抽离多个视图控制器间的共享数据端点
- 统一数据请求访问专属API端点,不再走视图控制器绑定的根路由
期望实现的目录结构:
Controllers ├─ Api │ └─ Data1Controller └─ View1Controller
问题复现
尝试使用Areas功能做路由隔离,Program.cs中路由配置代码如下:
app.UseRouting(); app.MapAreaControllerRoute("Api", "Api", "Api/{controller}/{action}/{id?}"); app.MapDefaultControllerRoute();
已为Api目录下的控制器标记[Area("Api")]特性,但访问/api/data路径时返回404错误。
故障原因
404是两个配置不匹配共同导致的:
- ASP.NET Core Area功能默认扫描的控制器路径为
根目录/Areas/<Area名称>/Controllers,当前将Api控制器放在Controllers/Api目录下,不在默认扫描范围内,路由系统无法匹配到对应控制器 - 若数据接口控制器标记了
[ApiController]特性,该特性默认优先启用属性路由,手写的传统约定路由(MapAreaControllerRoute、MapDefaultControllerRoute)对这类控制器默认不生效
推荐解决方案(适配渐进式改造场景,侵入性最低)
不需要使用Areas功能,通过自定义控制器约定统一给Api子目录下的控制器注入路由前缀,完全保留现有目录结构,不影响原有视图控制器的路由规则。
- 清空之前写的Area相关路由配置,在Program.cs的服务注册阶段添加自定义控制器约定:
builder.Services.AddControllersWithViews(options => { // 为Api子目录下的控制器统一配置路由前缀 options.Conventions.Add(new ApiNamespaceRouteConvention()); });
- 在项目中添加自定义约定实现类,可直接放在Program.cs同级命名空间下:
public class ApiNamespaceRouteConvention : IControllerModelConvention { public void Apply(ControllerModel controller) { // 识别命名空间以Controllers.Api结尾的控制器(对应Controllers/Api目录结构) if (controller.ControllerType.Namespace?.EndsWith("Controllers.Api") == true) { // 统一注入路由模板:前缀为api,匹配控制器名、Action名,可选id参数 controller.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = "api/[controller]/[action]/{id?}" } }); } } }
配置完成后,Controllers/Api目录下的所有控制器自动匹配/api/[controller]/[action]路径,外层普通视图控制器仍然走默认的/[controller]/[action]路由,完全兼容原有逻辑,不需要批量修改现有控制器代码。
注意:如果Api控制器标记了
[ApiController]特性,该方案同样生效,不需要额外调整。
备选方案(坚持使用Area功能的修正方式)
如果一定要使用Areas实现路由隔离,需要做两处修正:
- 调整控制器搜索规则,让框架能识别
Controllers/Api目录下的Area控制器,在服务注册阶段添加配置:
builder.Services.AddControllersWithViews() .AddRazorOptions(options => { // 仅当Api区域下有视图需求时需要配置视图搜索路径,纯接口可跳过 options.AreaViewLocationFormats.Add("/Controllers/Api/{1}/{0}.cshtml"); });
- 确保Api控制器同时标记正确的特性:
[Area("Api")] [ApiController] public class Data1Controller : ControllerBase { [HttpGet] public IActionResult Get() => Ok(); }
该方案后续新增全局过滤器、模型绑定时需要额外做命名空间判断,侵入性比推荐方案高,不适合渐进式改造场景。
验证方式
配置完成后重启应用,访问/api/data1/youraction路径即可命中对应Api控制器的接口,原有视图控制器的访问路径不受影响。
内容的提问来源于stack exchange,提问作者Cash
相关产品推荐
相关产品推荐

