ASP.NET Core 6路由无法区分带不同必填参数的同路由同动词动作
ASP.NET Core 6路由匹配问题
问题背景
在ASP.NET Core 6中,路由系统无法区分使用相同HTTP动词、相同路由模板,但必填参数不同的控制器动作。但该功能在ASP.NET Framework(传统Web API)中可以正常工作。
示例代码
以下是可复现问题的ASP.NET Core 6极简示例:
using Microsoft.AspNetCore.Mvc; namespace slim { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run(); } } [ApiController] public class SomeController : ControllerBase { [HttpPost] [Route("/somepath")] public async Task<ActionResult> Add([FromBody] SomeModel item) => Ok(); [HttpPost] [Route("/somepath")] public async Task<ActionResult> AddMany(int count) => Ok(); } public class SomeModel { public string? SomeProperty { get; set; } } }
复现方式
使用PowerShell执行以下任意请求,都会抛出AmbiguousMatchException异常:
Invoke-RestMethod "http://localhost:5186/somepath" -Method POST -Body @{ SomeProperty="value" } Invoke-RestMethod "http://localhost:5186/somepath" -Method POST Invoke-RestMethod "http://localhost:5186/somepath?count=4" -Method POST
疑问
- ASP.NET Core为何移除了ASP.NET Framework中支持的「通过必填参数区分同路由同HTTP动词动作」的功能?
- 有没有简便的方法恢复该功能?
已采用的解决方案
我使用了一个自定义特性来实现类似原Web API的行为,代码如下:
/// <summary> /// 确保仅当所有可从查询字符串绑定的必填参数都存在于路由数据或查询字符串中时, /// 此动作才会被视为当前请求的候选匹配项。 /// 注意:这原本是传统Web API的默认行为,但ASP.NET Core不再强制执行, /// 因此仅通过必填参数区分的动作重载现在会被判定为路由冲突(除非为其中一个动作应用此特性)。 /// </summary> public class RequireQueryParametersAttribute : ActionMethodSelectorAttribute { public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action) { foreach (var p in action.Parameters.OfType<ControllerParameterDescriptor>()) { // 仅检查必填的动作参数 if (!p.ParameterInfo.IsOptional) { // 仅检查允许从查询字符串绑定的参数 if (p.BindingInfo?.BindingSource == null || p.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Query)) { // 仅检查未出现在路由数据中的参数 if (!routeContext.RouteData.DataTokens.ContainsKey(p.Name)) { // 如果查询字符串中缺少该必填参数,则此动作对当前请求无效 if (!routeContext.HttpContext.Request.Query.ContainsKey(p.Name)) return false; } } } } return true; } }
内容的提问来源于stack exchange,提问作者Bob Meyers
相关产品推荐
相关产品推荐

