如何将Application Parts中的控制器映射到子路径?
给ASP.NET Core模块端点设置独立子路径的实现方案
要给每个基于Application Parts的模块设置独立的子路径前缀,有几种实用的方案,根据你的场景选就行:
方案一:利用区域(Area)结合Application Parts
这是最直接的方式,把每个模块对应一个Area,通过区域路由统一设置前缀:
- 模块控制器标记Area
在模块的所有控制器上添加[Area]特性,指定模块名称:
[Area("OrderModule")] public class OrderController : Controller { public IActionResult Index() { return View(); } }
- 配置区域路由
在Program.cs中添加区域路由模板,让所有该Area下的控制器自动带上子路径前缀:
var builder = WebApplication.CreateBuilder(args); // 加载模块的Application Parts builder.Services.AddControllersWithViews() .AddApplicationPart(typeof(OrderModule.OrderController).Assembly); var app = builder.Build(); // 配置区域路由 app.MapControllerRoute( name: "areaRoute", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); app.Run();
这样OrderModule下的所有端点都会自动映射到/OrderModule/xxx路径。
方案二:自定义路由约定统一添加前缀
如果不想用Area,可以通过自定义路由约定,给指定模块的控制器批量添加路由前缀:
- 创建自定义路由约定
实现IApplicationModelConvention,给目标程序集的控制器添加前缀:
public class ModuleRouteConvention : IApplicationModelConvention { private readonly string _routePrefix; private readonly Assembly _moduleAssembly; public ModuleRouteConvention(string routePrefix, Assembly moduleAssembly) { _routePrefix = routePrefix; _moduleAssembly = moduleAssembly; } public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { // 只处理目标模块的控制器 if (controller.ControllerType.Assembly == _moduleAssembly) { // 给控制器添加路由前缀 controller.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = $"{_routePrefix}/{controller.ControllerName}" } }); } } } }
- 注册约定并加载Application Parts
在Program.cs中注册这个约定,并关联对应的模块程序集:
var builder = WebApplication.CreateBuilder(args); var orderModuleAssembly = typeof(OrderModule.OrderController).Assembly; builder.Services.AddControllersWithViews() .AddApplicationPart(orderModuleAssembly) .AddMvcOptions(options => { // 添加自定义路由约定,设置前缀为/Order options.Conventions.Add(new ModuleRouteConvention("Order", orderModuleAssembly)); }); var app = builder.Build(); app.MapControllers(); app.Run();
这种方式下,OrderModule的控制器端点会映射到/Order/xxx路径。
方案三:用MapWhen隔离模块路由
如果需要更彻底的隔离(比如不同模块用不同的路由规则),可以用MapWhen创建独立的路由分支:
var builder = WebApplication.CreateBuilder(args); // 先注册共享服务 builder.Services.AddControllersWithViews(); var app = builder.Build(); // 处理OrderModule的请求 app.MapWhen(context => context.Request.Path.StartsWithSegments("/Order"), orderApp => { // 在分支中加载模块的Application Parts并配置路由 orderApp.UseRouting(); orderApp.UseEndpoints(endpoints => { endpoints.MapControllers() .AddApplicationPart(typeof(OrderModule.OrderController).Assembly); }); }); // 处理其他模块或主应用的请求 app.MapControllers(); app.Run();
这种方式下,所有以/Order开头的请求都会被路由到OrderModule的控制器,且可以给不同分支设置独立的中间件或路由规则。
内容的提问来源于stack exchange,提问作者Pavel Voronin
相关产品推荐
相关产品推荐

