ASP.NET Web API 中的可选查询字符串参数
Posted
技术标签:
【中文标题】ASP.NET Web API 中的可选查询字符串参数【英文标题】:Optional query string parameters in ASP.NET Web API 【发布时间】:2012-08-05 10:02:40 【问题描述】:我需要实现以下 WebAPI 方法:
/api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX
所有查询字符串参数都可以为空。也就是说,调用者可以指定从 0 到全部 5 个参数。
在 MVC4 测试版中,我曾经做过以下事情:
public class BooksController : ApiController
// GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
public string GetFindBooks(string author, string title, string isbn, string somethingelse, DateTime? date)
// ...
MVC4 RC 不再像这样了。如果我指定的参数少于 5 个,它会回复 404
说:
在控制器“Books”上找不到与请求匹配的操作。
什么是正确的方法签名,使其表现得像以前一样,而不必在 URL 路由中指定可选参数?
【问题讨论】:
让 [httpget] 行动起来。 如果我设置了所有参数,方法就会被调用;此外,它以Get
开头,因此它会自动与HTTP GET
方法绑定...
这就是 web api 路由的工作原理,asp.net/web-api/overview/web-api-routing-and-actions/…
是的。我知道它是如何工作的。在这种特殊情况下,我无法让它工作。
这是怎么编译的? string?
不是有效类型。您不能将 string
声明为可空类型,因为它是引用类型。
【参考方案1】:
此问题已在 MVC4 的常规版本中得到修复。 现在你可以这样做了:
public string GetFindBooks(string author="", string title="", string isbn="", string somethingelse="", DateTime? date= null)
// ...
一切都会开箱即用。
【讨论】:
我可以在这里使用 null 作为默认值吗?例如:字符串 author=null ? 是的,null
被认为是 constant expression,因此是 valid default value。
我想知道为什么我们必须提及默认值,即使是可选参数,如 here 所说。 C# 中的任何类型始终具有默认值,因此如果路由运行时没有从 URI 接收到该类型的默认值,它可能会采用该类型的默认值。这背后的技术原因是什么?我确定这与模型绑定器有关。
@RBT 这样可以匹配路由
我正在使用日期参数,如果我只是将它们设置为可为空,则无法正常工作。所以我必须将它设置为可空并将空设置为默认值,并相应地使用服务器端验证并返回错误消息。它奏效了。【参考方案2】:
按照 vijay 的建议,可以将多个参数作为单个模型传递。当您使用 FromUri 参数属性时,这适用于 GET。这告诉 WebAPI 从查询参数中填充模型。
结果是一个更简洁的控制器动作,只有一个参数。更多信息请见:http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
public class BooksController : ApiController
// GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
public string GetFindBooks([FromUri]BookQuery query)
// ...
public class BookQuery
public string Author get; set;
public string Title get; set;
public string ISBN get; set;
public string SomethingElse get; set;
public DateTime? Date get; set;
它甚至支持多个参数,只要属性不冲突。
// GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
public string GetFindBooks([FromUri]BookQuery query, [FromUri]Paging paging)
// ...
public class Paging
public string Sort get; set;
public int Skip get; set;
public int Take get; set;
更新: 为了确保这些值是可选的,请确保对模型属性使用引用类型或可为空值(例如 int?)。
【讨论】:
是的,但是单独的 [FromUri] 装饰器似乎不支持可选参数。 @JohnMeyer 您是正确的,使用 [FromUri] 并没有直接回答原始问题。它基本上说用 Uri 中的值填充这些模型。模型属性需要可以为空或引用类型,以便它们支持可选。添加了其他信息。 @AndrewC - 您能否详细说明何时/为什么需要使用可空值来确保值是可选的?如果您不使值可以为空(例如,属性int Skip
)并且没有指定该属性的查询参数,API 控制器方法仍将成功匹配请求,Skip
的值将只是该类型的默认值,在这种情况下为 0
@Clark - 如果不使用可为空的类型,您将不知道用户是否没有提供值并获得未初始化的类型值(0 表示 int)或者用户是否指定了 0。通过使用可为空您确定用户未定义它,因此您可以安全地在控制器操作中应用您的默认值。如果您从上面的示例中查看 Take,如果该操作收到 Take 的 0,应该怎么做?用户的意思是请求 0 条记录还是他们没有指定它,因此您应该获取所有记录。通常,如果您希望值类型(int、bool 等)是可选的,那么它应该可以为空。【参考方案3】:
对所有参数使用初始默认值,如下所示
public string GetFindBooks(string author="", string title="", string isbn="", string somethingelse="", DateTime? date= null)
// ...
【讨论】:
这是正确的过程,但一方面:DateTime
不可为空。我已经尝试改用DateTime?
,但是如果我在 HTTP 请求中只设置了一些参数,MVC 不会将请求映射到给定的方法。
您可以将日期作为字符串传递,并使用 DateTime.Parse() 函数在控制器函数中对其进行解析。
@MuhammadAmin, DateTime
不是 可为空 数据类型。您的代码不应编译,因为您无法将null
值分配给DateTime
类型的参数。也许,您应该将其更改为 DateTime?
,或者使用不同的值作为默认值,例如 DateTime.Now
。
@IvayloSlavov DateTime.Now 不是编译时间常数,因此不能指定为默认参数。
@GiriB,你确实是对的。 Datetime.Now
不能用于默认参数初始化,我已更正。【参考方案4】:
如果你想传递多个参数,那么你可以创建模型而不是传递多个参数。
如果你不想传递任何参数,那么你也可以跳过它,你的代码会看起来很整洁。
【讨论】:
这仅适用于请求正文中的 POST 参数 - url 中的参数仍然可以作为参数单独引用。【参考方案5】:不能为未声明为“optional
”的参数提供默认值
Function GetFindBooks(id As Integer, ByVal pid As Integer, Optional sort As String = "DESC", Optional limit As Integer = 99)
在你的WebApiConfig
config.Routes.MapHttpRoute( _
name:="books", _
routeTemplate:="api/controller/action/id/pid/sort/limit", _
defaults:=New With .id = RouteParameter.Optional, .pid = RouteParameter.Optional, .sort = UrlParameter.Optional, .limit = UrlParameter.Optional _
)
【讨论】:
其实可以。我使用的是 C#,而不是 VB.NET。以上是关于ASP.NET Web API 中的可选查询字符串参数的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core,以查询字符串为模板的 Web API RouteAttribute