使用属性路由时查询字符串不起作用

Chr*_*ton 60 c# query-string asp.net-web-api attributerouting asp.net-web-api-routing

我正在使用System.Web.Http.RouteAttributeSystem.Web.Http.RoutePrefixAttribute为我的Web API 2应用程序启用更干净的URL.对于我的大部分请求,我可以使用路由(例如Controller/param1/param2)或者我可以使用查询字符串(例如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...
    }
}
Run Code Online (Sandbox Code Playgroud)

当我使用路由请求时,两者都可以正常工作.但是,如果我使用查询字符串,它会失败,告诉我该路径不存在.

我已经尝试将以下内容添加到我的WebApiConfig.cs类' Register(HttpConfiguration config)函数(在默认路由之前和之后),但它没有做任何事情:

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+" });
Run Code Online (Sandbox Code Playgroud)

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

localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke
Run Code Online (Sandbox Code Playgroud)

和,

localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke
Run Code Online (Sandbox Code Playgroud)

但遗憾的是查询字符串版本不起作用!:(

更新

我完全删除了第二个Action,现在尝试使用带有可选参数的单个Action.我已经改变了我的路线属性,[Route("{name}/{drink}/{sport?}")]因为托尼建议让运动变得可空,但是现在localhost:12345/1/Names/Ted/coke由于某些原因这会阻止它成为一条有效的路线.查询字符串的行为与以前相同.

更新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...
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,使用查询字符串时找不到合适的路径,而使用路由方法时则没有.

Mos*_*ain 63

我正面临着同样的问题"如何将搜索参数包含为查询字符串?",而我正在尝试为我当前的项目构建一个web api.谷歌搜索后,以下工作正常:

Api控制器动作:

[HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")]

public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode)
{

}
Run Code Online (Sandbox Code Playgroud)

我通过邮递员尝试的网址:

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

http://localhost/PD is my hosted api
Run Code Online (Sandbox Code Playgroud)

  • @Kenta`GetProduct`不会出现在实际的URI中,看到`[Route()]`属性意味着URI是`/ PD/search?`这是可以接受的.不要忘记没有"REST标准"或规范,并给出了余地. (11认同)

Chr*_*ton 42

经过艰苦的琐事和谷歌搜索,我想出了一个"修复".我不知道这是不是理想/最佳做法/普通老错,但它解决了我的问题.

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

现在的一个例子是:

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

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

  • "痛苦堆叠"<snigger> (10认同)
  • 如果已在同一控制器中的另一个方法上标记[Route("")],则此方法无效 (6认同)

Ton*_*ony 19

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

[Route("{name}/{sport=Football}/{drink=Coke}")]
Run Code Online (Sandbox Code Playgroud)

分配值将允许它是可选的,因此您不必包含它,它将传递要指定的值.

我没有为此测试查询字符串,但它应该工作相同.

我只是重新阅读了这个问题而且我看到你有2个Get动词具有相同的路径,我相信这会引起冲突,因为路由不知道使用哪个,也许使用可选的参数将有所帮助.您还可以指定一个可以为null,并在方法中检查如何继续.

[Route("{name}/{sport?}/{drink?}")]
Run Code Online (Sandbox Code Playgroud)

然后检查方法中的变量以查看它们是否为null并根据需要进行处理.

希望这有帮助,有些人?大声笑

如果不是这个站点,它会有更多关于属性路由的细节.

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") { }
Run Code Online (Sandbox Code Playgroud)

目前,必须在可选参数上指定默认值才能使操作选择成功,但我们可以调查解除该限制.(如果这很重要,请告诉我们.)

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

[Route("countries/{name=USA}")]
public Country GetCountry(string name) { }
Run Code Online (Sandbox Code Playgroud)

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


Jur*_*uri 10

我的部分也是旁注.为了使queryString params起作用,您需要为方法参数提供一个默认值,以使其可选.就像通常调用C#方法时一样.

[RoutePrefix("api/v1/profile")]
public class ProfileController : ApiController
{

   ...

   [HttpGet]
   [Route("{profileUid}")]
   public IHttpActionResult GetProfile(string profileUid, long? someOtherId) 
   {
      // ...
   }

   ...

}
Run Code Online (Sandbox Code Playgroud)

这允许我像这样调用端点:

/api/v1/profile/someUid
/api/v1/profile/someUid?someOtherId=123
Run Code Online (Sandbox Code Playgroud)


bha*_*ddy 6

UsingRoute("search/{categoryid=categoryid}/{ordercode=ordercode}")将使您能够使用mosharaf hossain回答的查询字符串和内联路由参数。写这个答案,因为这应该是最佳答案和最佳方式。Route("")如果您有多个 Gets/Puts/Posts/Deletes,使用会导致问题。


con*_*att 6

这是@bhargav kishore mummadireddy 的答案的一个轻微偏差,但一个重要的偏差。他的答案会将查询字符串值默认为实际的非空值。此答案将默认它们为空。

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

这对我来说很重要,因为如果未指定查询字符串,我希望返回 400(错误请求),而不是让 ASP.NET 返回“无法在此控制器上找到此方法”错误。

[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.");
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)