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


212

我需要实现以下WebAPI方法:

/api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX

所有查询字符串参数都可以为null。也就是说,调用者可以指定0到5个参数中的所有参数。

MVC4 Beta中,我曾经执行以下操作:

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]。
user960567 2012年

2
如果设置了所有参数,则将调用该方法;此外,它以它开始,Get因此它自动与该HTTP GET方法绑定...
frapontillo 2012年

这就是Web api路由的工作方式,asp.net
actions

4
是。我知道它是如何工作的。我只是无法在这种特殊情况下使用它。
frapontillo 2012年

这个怎么编译?string?不是有效的类型。您不能将其声明string为可空类型,因为它是引用类型。
EkoostikMartin 2014年

Answers:


307

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

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

一切将立即可用。


我可以在这里使用null作为默认值吗?例如:字符串author = null?
鲍里斯·辛琴科

2
是,null被认为是常量表达式,因此是有效的默认值
JDawg '16

我不知道为什么我们还要为这里提到的可选参数提到默认值。C#中的任何类型始终具有默认值,因此,如果路由运行时未从URI接收到该类型的默认值,则该路由运行时可能会采用该默认值。这背后的技术原因是什么?我敢肯定这与模型活页夹有关。
RBT

@RBT,以便可以匹配路线
James Westgate

我正在使用日期参数,如果我只是将它们设置为nullable则无法正常工作。因此,我必须将其设置为nullable并将set null设置为默认值,并相应地使用服务器端验证并返回错误消息。有效。
阿塔H.19年

85

可以按照建议将多个参数作为单个模型传递。当您使用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?)。


4
是的,但是[FromUri]装饰器似乎并不支持可选参数。
约翰·迈耶

6
@JohnMeyer您使用[FromUri]不会直接回答原始问题是正确的。它基本上说用Uri中的值填充这些模型。models属性必须为可空值或引用类型,以使其支持可选属性。添加了其他信息。
安德鲁C

@AndrewC-您能否详细说明何时/为什么需要使用可为空的值以确保值是可选的?如果您不将值设为可为空(例如,property int Skip),并且没有为该属性指定查询参数,则API Controller方法仍将成功匹配请求,并且的值Skip将只是该类型的默认值,或0,在这种情况下
克拉克

2
@Clark-如果不使用可为空的类型,则不会知道用户是否未提供值并获得未初始化的类型值(对于int为0),或者用户是否指定了0。通过使用可为空的类型,您可以确保用户未定义该值因此,您可以安全地在控制器操作中应用默认设置。如果您从上面的示例中查看“执行”,那么如果操作获得“执行” 0,该怎么办?用户是要请求0条记录还是没有指定它,因此您应该获取所有记录。通常,如果您希望值类型(int,bool等)为可选,则该值类型应为可为空。
安德鲁C

70

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

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

1
这是正确的过程,但有一点:DateTime不可以为空。我已经尝试过使用它DateTime?,但是如果我仅在HTTP请求中设置一些参数,那么MVC不会将请求映射到给定的方法。
frapontillo 2012年

您可以将日期作为字符串传递,并使用DateTime.Parse()函数在控制器函数内部对其进行解析。
穆罕默德·阿明

1
@MuhammadAmin,DateTime不是空的数据类型。您的代码不应编译,因为您将无法null为类型的参数分配值DateTime。也许您应该将其更改为DateTime?,或将其他值(例如)使用不同的值DateTime.Now
Ivaylo Slavov

1
@IvayloSlavov DateTime.Now不是编译时间常量,因此无法将其分配为默认参数。
GiriB

@GiriB,您确实是对的。Datetime.Now无法在默认参数初始化中使用,我已纠正。
Ivaylo Slavov '18

1

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

如果您不想传递任何参数,则也可以在其中跳过,您的代码将看起来整洁。


1
这仅适用于请求正文中的POST参数-网址中的参数仍可以单独作为参数引用。
弥敦道

1

无法为未声明为' 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} _
      )

8
实际上,他们可以。我正在使用C#,而不是VB.NET。
frapontillo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.