查询string在使用属性路由时不起作用

我正在使用System.Web.Http.RouteAttributeSystem.Web.Http.RoutePrefixAttribute来为我的Web API 2应用程序启用更干净的URL。 对于我的大部分请求,我可以使用路由(例如Controller/param1/param2 )或者我可以使用查询string(例如Controller?param1=bob&param2=mary )。

不幸的是,我的一个控制器(也只有一个)失败了。 这是我的控制器:

 [RoutePrefix("1/Names")] public class NamesController : ApiController { [HttpGet] [Route("{name}/{sport}/{drink}")] public List<int> Get(string name, string sport, string drink) { // Code removed... } [HttpGet] [Route("{name}/{drink}")] public List<int> Get(string name, string drink) { // Code removed... } } 

当我请求使用路由时,两者都正常工作。 但是,如果我使用查询string,它会失败,告诉我,该path不存在。

我已经尝试添加以下内容到我的WebApiConfig.cs类的Register(HttpConfiguration config)函数(在Default路由之前和之后),但它什么也没做:

 config.Routes.MapHttpRoute( name: "NameRoute", routeTemplate: "{verId}/Names/{name}/{sport}/{drink}", defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional }, constraints: new { verId = @"\d+" }); 

所以为了清楚起见,我希望能够做到这一点:

 localhost:12345/1/Names/Ted/rugby/coke localhost:12345/1/Names/Ted/coke 

和,

 localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke localhost:12345/1/Names?name=Ted&drink=coke 

但遗憾的是查询string版本不起作用! 🙁

更新

我已经完全删除了第二个动作,现在试图只使用可选参数的单个动作。 我已经改变了我的路线属性为[Route("{name}/{drink}/{sport?}")] Tonybuild议让运动为空,但现在阻止localhost:12345/1/Names/Ted/coke从一个有效的路由出于某种原因。 查询string的行为与以前相同。

更新2我现在在我的控制器中有一个单独的动作:

 [RoutePrefix("1/Names")] public class NamesController : ApiController { [HttpGet] [Route("{name}/{drink}/{sport?}")] public List<int> Get(string name, string drink, string sport = "") { // Code removed... } } 

但仍然使用查询string找不到合适的path,而使用路由方法。

我正面临着“如何将search参数作为查询string?”的问题,同时我正在尝试为当前项目构buildWeb API。 谷歌search后,以下工作适合我:

Api控制器操作:

 [HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")] public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode) { } 

我通过邮递员试过的url:

 http://localhost/PD/search?categoryid=all-products&ordercode=star-1932 http://localhost/PD is my hosted api 

经过了很多艰辛的操作和谷歌search,我想出了一个“修复”。 我不知道这是不是理想/最好的做法/简单的错误,但它解决了我的问题。

我所做的只是添加[Route("")] ,除了我已经使用的路线属性。 这基本上允许Web API 2路由允许查询string,因为这现在是一个有效的路由。

现在是一个例子:

 [HttpGet] [Route("")] [Route("{name}/{drink}/{sport?}")] public List<int> Get(string name, string drink, string sport = "") { // Code removed... } 

这使得localhost:12345/1/Names/Ted/cokelocalhost:12345/1/Names?name=Ted&drink=coke有效。

使用属性路由,您需要指定默认值,以便它们是可选的。

 [Route("{name}/{sport=Football}/{drink=Coke}")] 

指定一个值将使它成为可选的,所以你不必包含它,它会传递值来指定。

我没有testing这个查询string,但它应该工作相同。

我只是重读了这个问题,我发现你有两个Get动词,但是我相信这会导致冲突,因为路由不知道要使用哪一个,可能使用可选的参数将有所帮助。 你也可以指定一个可以为null,并在方法中检查如何继续。

 [Route("{name}/{sport?}/{drink?}")] 

然后检查方法中的variables,看它们是否为空,并根据需要进行处理。

希望这有助于一些? 大声笑

如果不是这个网站,也许会有更多关于属性路由的细节。

http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

从该网站剪辑:

可选参数和默认值您可以通过向参数添加问号来指定参数是可选的,即:

 [Route("countries/{name?}")] public Country GetCountry(string name = "USA") { } 

目前,动作select必须在可选参数上指定一个默认值才能成功,但我们可以调查解除这个限制。 (请让我们知道这是否重要。)

默认值可以用类似的方式指定:

 [Route("countries/{name=USA}")] public Country GetCountry(string name) { } 

可选参数'?' 并且缺省值必须在参数定义中的内联约束之后出现。

只是我的一个侧面说明。 为了使queryString参数工作,您需要为您的方法参数提供一个默认值,以使其成为可选参数 。 就像通常调用C#方法时一样。

 [RoutePrefix("api/v1/profile")] public class ProfileController : ApiController { ... [HttpGet] [Route("{profileUid}")] public IHttpActionResult GetProfile(string profileUid, long? someOtherId) { // ... } ... } 

这使我可以像这样调用端点:

 /api/v1/profile/someUid /api/v1/profile/someUid?someOtherId=123 

使用Route("search/{categoryid=categoryid}/{ordercode=ordercode}")将使您能够使用querystrings和内联路由参数,如mosharaf hossain所回答的。 写这个答案,因为这应该是最好的答案和最好的办法。 如果您有多个获取/放置/post/删除,使用Route("")将导致问题。

既然你有[Route("{name}/{drink}/{sport?}")]作为属性路由,这个代码将永远不会被命中。

 config.Routes.MapHttpRoute( name: "NameRoute", routeTemplate: "{verId}/Names/{name}/{sport}/{drink}", defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional }, constraints: new { verId = @"\d+" }); 

所以只有属性路线[Route("{name}/{drink}/{sport?}")]在这里将会被尊重。 由于您的请求localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke ,所以在URL中不会有名称,运动或饮料匹配此属性路线。 匹配路由时我们不考虑查询string参数。

为了解决这个问题,你需要在你的属性path中设置所有3个选项。 然后它会匹配请求。

这是@bhargav kishore mummadireddy的答案的一个轻微的偏差,但是一个重要的偏差。 他的答案将默认querystring值为一个实际的非空值。 这个答案将默认为空。

它允许您通过path路由或使用查询string来调用控制器。 本质上,它将查询string的默认值设置为空,意味着它将始终被路由。

这对我很重要,因为如果没有指定查询string,而是让ASP.NET返回“无法在此控制器上find此方法”错误,我想返回400(错误请求)。

 [RoutePrefix("api/AppUsageReporting")] public class AppUsageReportingController : ApiController { [HttpGet] // Specify default routing parameters if the parameters aren't specified [Route("UsageAggregationDaily/{userId=}/{startDate=}/{endDate=}")] public async Task<HttpResponseMessage> UsageAggregationDaily(string userId, DateTime? startDate, DateTime? endDate) { if (String.IsNullOrEmpty(userId)) { return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(userId)} was not specified."); } if (!startDate.HasValue) { return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(startDate)} was not specified."); } if (!endDate.HasValue) { return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(endDate)} was not specified."); } } } 

我使用FromUri属性作为解决scheme

 [Route("UsageAggregationDaily")] public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)