Minimal API中CreatedAtRoute路由匹配异常问题排查
我正在创建一个Minimal Web API,定义了以下两个路由:
app.MapGet("/reports/{id:Guid}", GetReportById); app.MapPost("/reports", CreateReport);
对应的委托处理方法如下:
public static async Task<Results<Ok<ActivityReport>, NotFound, BadRequest<string>>> GetReportById( [AsParameters] ActivityReportingServices services, Guid id) { if (id == Guid.Empty) { return TypedResults.BadRequest("Id is not valid."); } var activityReport = await services.Context.ActivityReports.SingleOrDefaultAsync(report => report.Id == id); if (activityReport == null) { return TypedResults.NotFound(); } return TypedResults.Ok(activityReport); }
以及:
public static async Task<CreatedAtRoute<ActivityReport>> CreateReport( [AsParameters] ActivityReportingServices services, ActivityReportForCreateDTO activityReport) { var report = new ActivityReport() { Clients = activityReport.Clients }; services.Context.ActivityReports.Add(report); await services.Context.SaveChangesAsync(); return TypedResults.CreatedAtRoute(report, "/reports/{report.Id}"); }
ActivityReport类的Id成员为Guid类型。我的问题是,当CreateReport方法尝试返回TypedResults.CreatedAtRoute(report, $"/reports/{report.Id}")时,会抛出异常:“System.InvalidOperationException: No route matches the supplied values”。我曾尝试将路由"/reports/{id:Guid}"改为"/reports/{id}",并将GetReportById中的Id参数改为string类型,但问题仍未解决。请问我哪里操作错误?
你误用了CreatedAtRoute的参数格式。这个方法的第二个参数不是直接传URL路径,而是路由名称或者路由参数的键值对,用来匹配已定义的路由模板。
正确的两种实现方式:
命名路由+参数键值对
先给MapGet的路由设置一个名称,比如:app.MapGet("/reports/{id:Guid}", GetReportById).WithName("GetReportById");然后在
CreateReport中,通过路由名称和参数匹配:return TypedResults.CreatedAtRoute(report, new { id = report.Id });这里的匿名对象
new { id = report.Id }要和路由模板中的参数名{id:Guid}完全对应,ASP.NET会自动根据路由名称和参数生成正确的URL。直接使用路由模板匹配(不命名路由)
如果不想给路由命名,也可以直接传入参数键值对,框架会自动匹配对应的路由模板:return TypedResults.CreatedAtRoute(report, new { id = report.Id });注意:此时匿名对象的参数名必须和目标路由的参数名(
id)一致,类型也要匹配(Guid)。
你之前的错误点:
- 直接把拼接好的URL字符串传给
CreatedAtRoute,但这个方法并不接受完整URL作为参数,而是需要路由标识和参数集合,所以框架无法找到匹配的路由规则,抛出异常。 - 修改路由模板和参数类型的操作没有解决根本问题,因为核心错误是参数传递方式不对。
内容的提问来源于stack exchange,提问作者Peter Rundqvist

