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

ASP.NET Core中如何用MapDynamicControllerRoute自定义路由选择控制器

ASP.NET实现自定义路由绑定(类似Laravel风格)

问题描述

不想使用[Route("/hello")]路由属性或[controller=hello]/[action=Index]这类常规路由规则,希望通过自定义逻辑直接指定URL对应的控制器动作,例如:

if(context.Request.Path.Value == "/hello"){
   SomehowCallTheActionOnController("MyController", "MyAction", anyUrlValuesLikeId);
}

尝试过DynamicRouteValueTransformer,但因路由模板捕获了所有路径(得到values["all"]="hello/this/is/my/url"),手动设置控制器名称后无法生效;当前自行实现的代码需要手动处理依赖注入,且ActionRequest可能缺少必要属性,不确定是否规范。

解决方案

ASP.NET完全支持这种自定义路由绑定需求,以下是几种规范实现方式,均由框架处理控制器依赖注入和ActionContext实例化:

方式1:直接端点绑定控制器动作

通过MapGet/MapPost等方法直接将URL绑定到指定控制器的动作,框架自动注入控制器实例:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); // 注册控制器服务

var app = builder.Build();

// 自定义路由规则:将/hello映射到MyController的MyAction方法
app.MapGet("/hello", async (HttpContext context, MyController controller) =>
{
    // 获取URL参数(如id)
    var id = context.Request.Query["id"];
    // 调用控制器动作,框架自动处理DI
    var actionResult = await controller.MyAction(id);
    // 执行动作结果,框架自动管理ActionContext
    await actionResult.ExecuteResultAsync(new ActionContext(context, context.GetRouteData(), new ControllerActionDescriptor()));
});

app.Run();

方式2:利用DynamicRouteValueTransformer实现全局自定义路由

调整路由模板配合DynamicRouteValueTransformer,让框架根据自定义逻辑匹配控制器动作:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// 注册自定义路由转换器
builder.Services.AddSingleton<DynamicRouteValueTransformer, MyCustomRouteTransformer>();

var app = builder.Build();

app.UseRouting();
// 匹配所有路径,交由自定义转换器处理
app.MapDynamicControllerRoute<MyCustomRouteTransformer>("{*path}");

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();

// 自定义路由转换器
public class MyCustomRouteTransformer : DynamicRouteValueTransformer
{
    public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext context, RouteValueDictionary values)
    {
        var path = values["path"] as string;
        RouteValueDictionary resultValues = values;

        // 自定义路由匹配逻辑
        if (path == "hello")
        {
            resultValues = new RouteValueDictionary
            {
                ["controller"] = "MyController",
                ["action"] = "MyAction",
                ["id"] = context.Request.Query["id"] // 传递URL参数
            };
        }
        else if (path == "user/profile")
        {
            resultValues = new RouteValueDictionary
            {
                ["controller"] = "UserController",
                ["action"] = "Profile"
            };
        }

        return new ValueTask<RouteValueDictionary>(resultValues);
    }
}

方式3:手动添加控制器动作端点

通过ControllerActionEndpointDataSource获取控制器动作的端点描述,手动绑定到指定URL:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();

app.UseRouting();

// 获取控制器动作的端点数据源
var dataSource = app.Services.GetRequiredService<ControllerActionEndpointDataSource>();
// 找到目标控制器动作的端点描述
var targetAction = dataSource.Endpoints
    .OfType<ControllerActionEndpoint>()
    .First(e => e.ControllerName == "MyController" && e.ActionName == "MyAction");

app.UseEndpoints(endpoints =>
{
    // 自定义路由:将/hello映射到目标动作
    endpoints.MapGet("/hello", context =>
    {
        // 设置路由数据,告知框架要调用的控制器和动作
        context.GetRouteData().Values["controller"] = "MyController";
        context.GetRouteData().Values["action"] = "MyAction";
        // 传递URL参数
        context.GetRouteData().Values["id"] = context.Request.Query["id"];
        
        // 让框架执行控制器动作,自动处理DI和ActionContext
        return endpoints.RequestDelegateFactory.Create(targetAction)(context);
    });
});

app.Run();

总结

以上三种方式都能实现类似Laravel中Route::get('/user', [UserController::class, 'index']);的自定义路由效果,无需手动处理依赖注入或ActionContext的完整初始化,完全遵循ASP.NET的框架规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:15:43