ASP.NET Core 8 Web API:如何同时支持路由与查询参数绑定?
问题原因
当你同时给方法添加两个[Route]属性时,由于其中一个路由模板包含{id}参数,ASP.NET Core会默认将id参数的绑定源设置为路由。此时即便请求匹配的是不带{id}的/GetMyData路由,框架仍会优先尝试从路由中获取id值,完全忽略查询字符串中的参数,最终因路由内无id导致请求失败。
解决方案
以下是几种可行的实现方式,都能让接口同时兼容路由参数和查询字符串参数:
方案一:拆分参数并合并取值
显式定义两个参数分别绑定路由和查询字符串,在方法内合并取值并校验必填性:
[HttpGet] [Route("GetMyData/{id}")] [Route("GetMyData")] public async Task<ActionResult> GetMyData([FromRoute] int? idRoute, [FromQuery(Name = "id")] int? idQuery) { var id = idRoute ?? idQuery; if (!id.HasValue) { return BadRequest("必须提供id参数"); } return await _dataService.GetMyData(id.Value).ConfigureAwait(false); }
方案二:可选路由参数+查询回退
将路由中的id设为可选,通过两个参数分别接收路由和查询值,再做回退处理:
[HttpGet("GetMyData/{id?}")] public async Task<ActionResult> GetMyData([FromRoute] int? id, [FromQuery] int? queryId) { var actualId = id ?? queryId; if (!actualId.HasValue) { return BadRequest("请提供id参数"); } return await _dataService.GetMyData(actualId.Value).ConfigureAwait(false); }
方案三:自定义绑定源(单参数实现)
创建自定义绑定属性,让参数支持同时从路由或查询字符串获取值:
// 自定义绑定属性 public class FromRouteOrQueryAttribute : Attribute, IBindingSourceMetadata { public BindingSource BindingSource => CompositeBindingSource.Create( new[] { BindingSource.Path, BindingSource.Query }, nameof(FromRouteOrQueryAttribute)); }
在接口方法中使用该属性:
[HttpGet] [Route("GetMyData/{id}")] [Route("GetMyData")] public async Task<ActionResult> GetMyData([FromRouteOrQuery] int id) { return await _dataService.GetMyData(id).ConfigureAwait(false); }
注:由于[ApiController]会自动做模型验证,若请求未提供任何来源的id,会直接返回400错误。
内容的提问来源于stack exchange,提问作者Eric Evans
相关产品推荐
相关产品推荐

