C# ASP.NET Web API中的可选查询字符串参数

C# ASP.NET Web API中的可选查询字符串参数,c#,url,asp.net-web-api,query-string,C#,Url,Asp.net Web Api,Query String,我需要实现以下WebAPI方法: /api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX 所有查询字符串参数都可以为null。也就是说,调用方可以指定从0到所有5个参数 在MVC4测试版中,我曾经做过以下工作: public class BooksController : ApiController { // GET /api/books?author=tolk&ti

我需要实现以下WebAPI方法:

/api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX
所有查询字符串参数都可以为null。也就是说,调用方可以指定从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) 
    {
        // ...
    }
}
MVC4RC的行为不再像这样了。如果我指定的参数少于5个,它会用
404
回复说:

在与请求匹配的控制器“Books”上未找到任何操作


不必在URL路由中指定可选参数,正确的方法签名是什么使其行为与以前一样?

对所有参数使用初始默认值,如下所示

public string GetFindBooks(string author="", string title="", string isbn="", string  somethingelse="", DateTime? date= null) 
{
    // ...
}

此问题已在MVC4的常规版本中修复。 现在您可以执行以下操作:

public string GetFindBooks(string author="", string title="", string isbn="", string  somethingelse="", DateTime? date= null) 
{
    // ...
}

而且一切都会开箱即用。

如果要传递多个参数,则可以创建模型,而不是传递多个参数


如果你不想传递任何参数,那么你也可以跳过它,你的代码会看起来整洁干净。

对于未声明为“
可选”
”的参数,不能提供默认值

 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} _
      )

按照vijay的建议,可以将多个参数作为单个模型传递。当您使用FromUri参数属性时,这适用于GET。这将告诉WebAPI根据查询参数填充模型

结果是一个更干净的控制器操作,只有一个参数。有关更多信息,请参阅:

只要属性不冲突,它甚至支持多个参数

// 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; }
}
更新


为了确保这些值是可选的,请确保对模型属性使用引用类型或nullables(例如int?)。

put[httpget]on action。如果我设置了所有参数,将调用该方法;此外,它以
Get
开始,因此它自动与
httpget
方法绑定……这就是webapi路由的工作原理,是的。我知道它是怎么工作的。在这种特殊情况下,我就是无法让它工作。它是如何编译的<代码>字符串?不是有效的类型。您不能将
string
声明为可空类型,因为它是引用类型。这是正确的过程,但有一点:
DateTime
不可空。我已经尝试改用
DateTime?
,但是如果我在HTTP请求中只设置了一些参数,MVC不会将请求映射到给定的方法。您可以将日期作为字符串传递,并在控制器函数中使用DateTime.parse()函数对其进行解析。@MuhammadAmin,
DateTime
不是可为空的数据类型。您的代码不应编译,因为您无法将
null
值分配给
DateTime
类型的参数。也许,您应该将其更改为
DateTime?
,或者对默认值使用不同的值,如
DateTime.Now
@IvayloSlavov DateTime.Now不是编译时常量,因此不能将其指定为默认参数。@GiriB,您的确是对的<代码>日期时间。现在不能用于默认参数初始化,我已更正。这仅适用于请求正文中的POST参数-url中的参数仍然可以作为参数单独引用。实际上,它们可以。我使用的是C#,而不是VB.NET.Yes,但是[FromUri]装饰器本身似乎不支持可选参数。@JohnMeyer您使用[FromUri]没有直接回答原始问题是正确的。它基本上说用Uri中的值填充这些模型。模型属性必须是可空的或引用类型,才能支持可选。添加了其他信息。@AndrewC-您能否详细说明何时/为什么需要使用nullables来确保值是可选的?如果不使值为空(例如,属性
int Skip
),并且没有指定该属性的查询参数,则API控制器方法仍将成功匹配请求,
Skip
的值将只是该类型的默认值,或者这个0case@Clark-如果不使用可为null的类型,您将不知道用户是否未提供值并获得未初始化的类型值(int为0),或者用户是否指定了0。通过使用nullable,您可以确保用户未定义它,因此您可以在控制器操作中安全地应用默认值。如果您查看上面示例中的Take,那么如果收到0 for Take,该操作应该怎么做?用户是否打算请求0条记录,或者他们没有指定,因此您应该获取所有记录。通常,如果您希望值类型(int、bool等)是可选的,那么它应该可以为null。我可以在这里使用null作为默认值吗?例如:string author=null?是的,
null
被认为是a,因此是a。我想知道为什么我们必须提到默认值,即使是前面提到的可选参数。C#中的任何类型都始终有一个默认值,因此如果路由运行时没有从URI接收到该类型的默认值,它可能会采用该类型的默认值。这背后的技术原因是什么?。我确信这与模型绑定器有关。@RBT以便路线可以匹配。我使用的是日期参数,如果我只是将它们设置为nullable,则不起作用。因此,我必须将其设置为null,并将null设置为默认值,并相应地使用服务器端验证并返回错误消息。成功了。
// 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; }
}