【发布时间】:2017-01-16 22:26:58
【问题描述】:
上下文
我正在尝试构建一个 ASP.NET Core Web API 控制器,它将公开以下具有特定语义的方法:
/api/experimental/cars — 获取整个集合
[HttpGet("/api/experimental/cars/")]
public Task<List<Car>> AllCars()
/api/experimental/cars/123 — 通过 id "123" 获取汽车
[HttpGet("/api/experimental/cars/{carId}")]
public Task<Car> CarById([FromRoute] string carId)
/api/experimental/cars?nameFilter=Maz — 获取与 nameFilter = "Maz" 匹配的汽车
[HttpGet("/api/experimental/cars/{nameFilter?}")]
public Task<List<Car>> CarsByNameFilter([FromQuery] string nameFilter = "")
/api/experimental/cars?nameFilter=Maz&rating=2 — 获取匹配 nameFilter = "Maz" 且评分大于或等于 2 的汽车
[HttpGet("/api/experimental/cars/{nameFilter?}/{rating?}")]
public Task<List<Car>> CarsByNameAndRatingFilter([FromQuery] string nameFilter = "", [FromQuery] int rating = 1)
注意:我真的很想保持控制器类干净,并且每个 Web API 路由都有一个方法——这可能吗?
问题
如您所料,这些 API 定义存在问题。基本上,AllCars 拦截了几乎所有的请求。 (当我至少能够让/api/experimental/cars/{carId} 工作时,基于查询字符串的 API 仍然无法工作并被另一种方法拦截......
我尝试了许多可能的路由语法来表达我想要的,但没有运气。是否甚至可以使用默认路由机制,或者我需要实现自己的路由器类或中间件或其他东西?
更新 1:问题定义
我知道我可以将至少三个方法及其路由加入到单个 WebAPI 方法中,该方法对接收到的参数很智能。请注意,这正是我想要避免的。
为什么?
原因 1:我看到在非 .NET 路由器中,它运行良好,并且没有技术上不可能实现基于语义的路由解析。
原因 2:我认为上面提到的所有四种 URL 模式都是四种不同的路由。可能有人不同意我的观点,但没关系,但就我的目的而言,方法和路线不同,必须保持不同。
原因 3.1:这使控制器代码保持干净。每种方法只处理一种特定情况。参数名称足以正确解析路线(至少在人类头脑中,因此机器也可以做到 - 将算法形式化很容易)。如果客户端使用不受支持的查询参数发出请求,它应该会导致 HTTP 404 Not Found 或 HTTP 400 Bad Request -- 完全没问题(客户端宁愿构造正确的 URL)。
原因 3.2:相反,如果我加入方法并使用更通用的路由,我的实现需要在参数组合方面“聪明”。这实际上是将路由抽象泄漏到它不属于我的体系结构的层中。复杂的验证是我不想在 Controller 中看到的另一件事——代码越少越好。
更新 2:Nancy — 另一个 .NET 示例(其他 .NET Core WebApi)
有 Nancy(一个 .NET 框架)完美地处理了路由的这一方面:https://github.com/NancyFx/Nancy/wiki/Defining-routes#pattern 问题是在我的项目中我们没有使用它...... Nancy 是一个完美的工具示例将路由语义的准确定义留给客户端,而不是对 什么是路由 vs 什么不是执行过于严格的规则。
【问题讨论】:
-
可选的路由参数是你的问题的原因
-
车牌号是字母数字还是只有数字?
-
@nkosi 我知道问题出在哪里。 :) 汽车 ID 是字符串,而不是数字。
-
它是否遵循一种模式,您可以在路由时应用约束以唯一标识它。
-
如果您在谈论 /api/experimental/cars/123,那么是的。这个定位到一辆 ID 为“123”(可能存在也可能不存在)的汽车。
标签: c# asp.net-core asp.net-core-webapi