C# 如何在ASP.NET Core中创建多个WebApi enpoint

C# 如何在ASP.NET Core中创建多个WebApi enpoint,c#,asp.net-core,asp.net-web-api,query-parameters,C#,Asp.net Core,Asp.net Web Api,Query Parameters,所以我需要创建三个端点- /空气污染指数/城市 /api/城市/:id /api/城市?国家/地区= 第一个端点应该是在我键入时- www.mywebsite/api/cities 第二个端点应该是在我键入时- www.mywebsite/api/cities/1 第三个端点应该是在我键入时- www.mywebsite/api/cities?country=加拿大 我尝试了以下方法: [HttpGet] 公共异步任务GetCities{/*…*/}//应从DB获取所有城市 [HttpGet{i

所以我需要创建三个端点- /空气污染指数/城市 /api/城市/:id /api/城市?国家/地区=

第一个端点应该是在我键入时- www.mywebsite/api/cities

第二个端点应该是在我键入时- www.mywebsite/api/cities/1

第三个端点应该是在我键入时- www.mywebsite/api/cities?country=加拿大

我尝试了以下方法:

[HttpGet] 公共异步任务GetCities{/*…*/}//应从DB获取所有城市 [HttpGet{id:int},Name=GetCityById] 公共异步任务GetCityById[FromRoute]int id{/*…*/}//应该只从DB获取一个城市 [HttpGet{国家:alpha}] 公共异步任务GetCitiesByCountry[FromQuery]字符串country{/*…*/}//应获取country中的所有城市
前两个端点工作得很好,但当我尝试使用查询参数获取我通过的国家的所有城市时,我似乎触发了第一个端点,即/api/cities,而不是/api/cities?country=

,在我找到解决方案之前,您的代码中有一个问题。在上一个操作中定义[HttpGet{country:alpha}]就是指定一个路由模板,在该模板中,您希望URL的路径部分中存在一个国家/地区路由参数,例如。https://www.example.org/i/am/a/path. 但是,当您使用FromQuery属性标记字符串country时,它将只绑定查询字符串中的国家,而不绑定路径

指定路由模板还意味着,当您向/api/cities?country=blah发送请求时,它将永远不会匹配您的GetCitiesByCountry操作,因为它希望它的格式为/api/cities/country,因为这是您使用路由模板指定的格式。因此,您需要做的第一件事是将您的最后一个操作更改为:

[HttpGet]
public async Task<IActionResult> GetCitiesByCountry([FromQuery] string country)
然后用它装饰城市:

如果我们现在向/api/cities?country=blah发送一个请求,那么GetCities将被排除在选择之外,因为请求有一个查询字符串,因此GetCitiesByCountry将按照我们想要的方式执行。但是,如果我们将请求发送到/api/cities,我们可能仍然会得到不明确的操作选择错误,因为请求不包含查询字符串,因此GetCities和GetCitiesByCountry似乎仍然与请求匹配。但是请求确实成功了,并且按照我们的要求运行GetCities

原因可以归纳为以下几点,ActionMethodSelectorAttribute本身实现了这一点:

动作约束具有使应用了约束的动作比未应用约束的动作更匹配的次要效果。考虑两个动作,“A”和“B”具有相同的动作和控制器名称。操作“A”只允许通过约束使用HTTP POST方法,而操作“B”没有约束。如果传入请求是POST,则“a”被认为是最佳匹配,因为它既匹配又有约束。如果传入的请求使用任何其他动词,“A”由于其约束将对选择无效,因此“B”是最佳匹配


这意味着因为我们定义了IgnoreIfRequestHasQueryString的自定义约束,它成功地匹配了/api/cities,所以GetCities方法被认为是首选方法,因此没有歧义。

在我找到解决方案之前,您的代码中有一个问题。在上一个操作中定义[HttpGet{country:alpha}]就是指定一个路由模板,在该模板中,您希望URL的路径部分中存在一个国家/地区路由参数,例如。https://www.example.org/i/am/a/path. 但是,当您使用FromQuery属性标记字符串country时,它将只绑定查询字符串中的国家,而不绑定路径

指定路由模板还意味着,当您向/api/cities?country=blah发送请求时,它将永远不会匹配您的GetCitiesByCountry操作,因为它希望它的格式为/api/cities/country,因为这是您使用路由模板指定的格式。因此,您需要做的第一件事是将您的最后一个操作更改为:

[HttpGet]
public async Task<IActionResult> GetCitiesByCountry([FromQuery] string country)
然后用它装饰城市:

如果我们现在向/api/cities?country=blah发送一个请求,那么GetCities将被排除在选择之外,因为请求有一个查询字符串,因此GetCitiesByCountry将按照我们想要的方式执行。但是,如果我们将请求发送到/api/cities,我们可能仍然会得到不明确的操作选择错误,因为请求不包含查询字符串,因此GetCities和GetCitiesByCountry似乎仍然与请求匹配。但是请求确实成功了,并且按照我们的要求运行GetCities

原因可以归纳为以下几点,ActionMethodSelectorAttribute本身实现了这一点:

动作约束具有使应用了约束的动作比未应用约束的动作更匹配的次要效果。考虑两个动作,“A”和“B”具有相同的动作和控制器名称。操作“A”仅允许通过约束和 操作“B”没有约束。如果传入请求是POST,则“a”被认为是最佳匹配,因为它既匹配又有约束。如果传入的请求使用任何其他动词,“A”由于其约束将对选择无效,因此“B”是最佳匹配


这意味着因为我们定义了IgnoreIfRequestHasQueryString的自定义约束,它成功地匹配了/api/cities,所以GetCities方法被认为是首选方法,因此没有歧义。

太棒了!这对我起了作用,我学到了一些新东西。非常感谢!太神了这对我起了作用,我学到了一些新东西。非常感谢!
[HttpGet]
[IgnoreIfRequestHasQueryString]
public async Task<IActionResult> GetCities()