Optional query string parameters in ASP.NET Web API
Solution 1
This issue has been fixed in the regular release of MVC4. Now you can do:
public string GetFindBooks(string author="", string title="", string isbn="", string somethingelse="", DateTime? date= null)
{
// ...
}
and everything will work out of the box.
Solution 2
It's possible to pass multiple parameters as a single model as vijay suggested. This works for GET when you use the FromUri parameter attribute. This tells WebAPI to fill the model from the query parameters.
The result is a cleaner controller action with just a single parameter. For more information see: 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; }
}
It even supports multiple parameters, as long as the properties don't conflict.
// 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; }
}
Update:
In order to ensure the values are optional make sure to use reference types or nullables (ex. int?) for the models properties.
Solution 3
Use initial default values for all parameters like below
public string GetFindBooks(string author="", string title="", string isbn="", string somethingelse="", DateTime? date= null)
{
// ...
}
Solution 4
if you want to pass multiple parameters then you can create model instead of passing multiple parameters.
in case you dont want to pass any parameter then you can skip as well in it, and your code will look neat and clean.
Solution 5
Default values cannot be supplied for parameters that are not declared 'optional
'
Function GetFindBooks(id As Integer, ByVal pid As Integer, Optional sort As String = "DESC", Optional limit As Integer = 99)
In your 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} _
)
Related videos on Youtube
frapontillo
Updated on July 18, 2022Comments
-
frapontillo almost 2 years
I need to implement the following WebAPI method:
/api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX
All of the query string parameters can be null. That is, the caller can specify from 0 to all of the 5 parameters.
In MVC4 beta I used to do the following:
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 doesn't behave like this anymore. If I specify fewer than 5 parameters, it replies with a
404
saying:No action was found on the controller 'Books' that matches the request.
What is the correct method signature to make it behave like it used to, without having to specify the optional parameter in the URL routing?
-
Imran Qadir Baksh - Baloch over 11 yearsput [httpget] on action.
-
frapontillo over 11 yearsIf I set all of the parameters the method gets called; furthermore it starts with
Get
so it is automatically bound with theHTTP GET
method... -
Imran Qadir Baksh - Baloch over 11 yearsThis is how web api routing works, asp.net/web-api/overview/web-api-routing-and-actions/…
-
frapontillo over 11 yearsYes. I know how it works. I just can't get it to work under THIS particular circumstance.
-
EkoostikMartin about 10 yearsHow did this even compile?
string?
is not a valid type. You can't declarestring
as a nullable type since it is a reference type. -
frapontillo about 10 years@EkoostikMartin you are right, it probably was a quick gist of code I wrote just for the purpose of understanding why I wasn't able to default to
null
. As I recall, the real issue was withDateTime
which couldn't be defaulted until the beta release. Also, this question is from 1 year and a half ago.
-
-
frapontillo over 11 yearsThis is the correct procedure but for one thing:
DateTime
is not nullable. I have already tried to useDateTime?
instead, but then MVC does not map the request to the given method if I set only some of the parameters in my HTTP request. -
Muhammad Amin over 11 yearsyou can pass date as a string and parse it inside your controller function using DateTime.Parse() function.
-
Andy over 11 yearsThis is only true for the POST parameters in the request body - params in the url can still be reference individually as arguments.
-
frapontillo about 11 yearsActually, they can. I'm using C#, not VB.NET.
-
Ivaylo Slavov about 10 years@MuhammadAmin,
DateTime
is not a nullable data type. Your code should not compile, as you would not be able to assign anull
value to a parameter of typeDateTime
. Perhaps, you should change it toDateTime?
, or use different value for a default likeDateTime.Now
. -
John Meyer about 8 yearsYes, but the [FromUri] decorator alone does not appear to support optional parameters.
-
Andrew C almost 8 years@JohnMeyer You are correct using [FromUri] doesn't directly answer the original question. It basically says populate these models with the values from the Uri. The models properties would need to be nullable or a reference type in order for them to support being optional. Added additional information.
-
Boris Zinchenko almost 8 yearsCan I use null here as a default? For instance: string author=null ?
-
JDawg over 7 years
-
RBT over 7 yearsI wonder why we have to mention default values even for optional parameters as said here . Any type in C# always have a default value so routing run-time could have taken the type's default value if it didn't receive it from the URI. What is the technical reason behind this?. I'm sure this has something to do with model binder.
-
James Westgate almost 7 years@RBT So that the route can be matched
-
GiriB almost 6 years@IvayloSlavov DateTime.Now is not a compile time constant so it cant be assigned as the default parameter.
-
Ivaylo Slavov almost 6 years@GiriB, you're right indeed.
Datetime.Now
cannot be used in default parameter initialization, I stand corrected. -
Clark over 5 years@AndrewC - Could you elaborate on when/why you need to use nullables to ensure values are optional? If you don't make the values nullable (for ex, property
int Skip
) and there is no query param for that property specified, the API Controller method will still successfully match the request and the value forSkip
will just be the default value for that type, or 0 in this case -
Andrew C over 5 years@Clark - Without using a nullable type you won't know if the user did not provide a value and got the uninitialized type value (0 for int) or if the user specified 0. By using nullable you are sure the user left it undefined therefore you can safely apply your default in the controller action. If you look at Take from the example above, what should the action do if it received a 0 for Take? Did the user mean to request 0 records or did they not specify it and therefore you should take all records. Generally if you want a value type (int, bool, etc.) to be optional then it should be nullable.
-
Atta H. almost 5 yearsI was using date parameters and if i just set them to nullable was not working. So i have to set it nullable and the set null as default value, and use server side validation accordingly and return error messages back. It worked.
-
Lukas over 3 years@AttaH. That's strange because at least on Core 3.1 objects of nullable types default to
null
for me without having to set them explicitly. -
yogendra maarisetty over 2 years@frapontillo I want to do something like. I have two optional params. I want the user to pass at least any one of the param but not both combined