The ASP.NET Core framework automatically parses query strings (i.e. ?name=Dune&year=2021) into HttpContext.Request.Query and maps the query string values to parameters in the action method (if you’ve added them).
You can get the mapped query string values by adding action parameters, like this:
[HttpGet("search")]
public IActionResult Search(string name, int year)
Code language: C# (cs)
Or you can use HttpContext.Request.Query directly (which is useful in many scenarios):
string name = HttpContext.Request.Query["name"];
Code language: C# (cs)
This can either return null (if the key is missing), a single string, or a comma-separated string (i.e. “Dune,Matrix”) if there are multiple values for the key.
Table of Contents
Automatically mapping the query string
The framework will automatically map the query string to action parameters. It tries to convert to the proper type and will then do validation against any data annotations you’ve added (such as [Required]). In most cases, you should take advantage of this automatic mapping instead of using HttpContext.Request.Query directly.
Note: It does a case-insensitive comparison when trying to map the query string keys to parameter/property names.
Primitive parameters
Here’s an example of adding primitive parameters to the action method:
[HttpGet("search")]
public IActionResult Search(string name, int year, DateTime lastUpdated)
{
Console.WriteLine($"name={name} year={year} lastUpdated={lastUpdated}");
//rest of method
}
Code language: C# (cs)
Here’s a request with a query string:
GET /movies/search/?name=Dune&year=2021&lastUpdated=2021-11-12
Code language: plaintext (plaintext)
The framework will parse the query string and map its values to the primitive parameters. Here’s what this outputs:
name=Dune year=2021 lastUpdated=11/21/2021 12:00:00 AM
Code language: plaintext (plaintext)
Model parameter
You can encapsulate the parameters in a model class:
public class MovieQuery
{
public string Name { get; set; }
public int Year { get; set; }
}
Code language: C# (cs)
Add this MovieQuery model class as a parameter on the action method and use the [FromQuery] attribute:
[HttpGet("search")]
public IActionResult Search([FromQuery] MovieQuery movieQuery)
{
Console.WriteLine($"name={movieQuery.Name} year={movieQuery.Year}");
//rest of method
}
Code language: C# (cs)
Here’s a request with a query string:
GET /movies/search/?name=Dune&year=1984
Code language: plaintext (plaintext)
The framework will parse the query string and map the values to the MovieQuery model. Here’s what this outputs:
name=Dune year=1984
Code language: plaintext (plaintext)
Do you have to use [FromQuery] with a model parameter?
Yes, otherwise you’ll get error response 415 – Unsupported Media Type when it tries to map the query string.
Use [FromQuery(Name = “something”] when the parameter name is different
Let’s say the requests will be sent with query strings using names that are different than the parameters / properties that you’re mapping to. In that case, you can use the [FromQuery(Name = “something”)] attribute to change the mapping for a specific parameter / property.
For example, let’s say you’re getting requests with a query string that looks like this:
?movie.name=Dune&movie.year=1984
Code language: plaintext (plaintext)
You can get this to map to “name” and “year” like this:
public class MovieQuery
{
[FromQuery(Name = "movie.name")]
public string Name { get; set; }
[FromQuery(Name = "movie.year")]
public int Year { get; set; }
}
Code language: C# (cs)
This will result in the following mapping:
- movie.name => MovieQuery.Name
- movie.year => MovieQuery.Year
Multiple values for the same key
Query string keys can have multiple values. Here’s an example. The year key has two values:
GET /movies/search/?name=Dune&year=2021&year=1984
When this request comes in, it’ll be parsed into HttpContext.Request.Query, which will look like this:
{
"name" = ["Dune"]
"year" = ["2021", "1984"]
}
Code language: plaintext (plaintext)
Only the first value of the key will be automatically mapped to a parameter / property (i.e. int year would be set to 2021).
Furthermore, the values are actually StringValues objects. These are specialized collections of strings. There are a few things to know about how StringValues work, which I’ll describe below in the context of using HttpContext.Request.Query.
HttpContext.Request.Query[“key”] will return comma-separated values
If multiple years are sent in the query string:
GET /movies/search/?name=Dune&year=2021&year=1984
Code language: plaintext (plaintext)
And you’re using the indexer to get the value:
string year = HttpContext.Request.Query["year"];
Code language: C# (cs)
It’ll return the years as a comma-separated value:
"2021,1984"
Code language: plaintext (plaintext)
This isn’t the same as sending a comma-separated list in the query string:
GET /movies/search/?name=Dune&year=2021,1984
Code language: plaintext (plaintext)
When multiple values are sent like this, “2021,1984” are treated as a single value in HttpContext.Request.Query, not two different values. Some devs may prefer to deal with the multiple values like this, instead of adding the same key repeatedly. It all depends on how you’re going to be using the values.
Use HttpContext.Request.Query[“key”][0] to get the first value
To get the first value, use:
HttpContext.Request.Query["key"][0]
Code language: C# (cs)
Do this if you aren’t using automatic mapping and only want the first value.
Note: Always check if the key exists if you’re using the indexer like this.
Using the StringValues collection
StringValues is a collection. When you’re dealing with multiple values, you don’t need to convert StringValues to a string and deal with the comma-separated string (i.e. “2021,1984”). To simplify things, you can use the collection functionality of StringValues.
- You can loop through the values.
foreach(var value in HttpContext.Request.Query["year"])
{
Console.WriteLine(value);
}
Code language: C# (cs)
- You can check how many values there are.
HttpContext.Request.Query["year"].Count
Code language: C# (cs)
- You can get a string array.
string[] years = HttpContext.Request.Query["year"].ToArray();
var movies = movieRepository.SearchForYears(years);
Code language: C# (cs)
Note: In this example, you could also convert the comma-separated string into a list of integers if you need the individual values as integers.
Check if a query string key has been supplied
When the key is required
Add the required key as a parameter (or property on a model) and apply the [Required] attribute.
using System.ComponentModel.DataAnnotations;
[HttpGet("search")]
public IActionResult Search([Required] string name)
Code language: C# (cs)
When the key isn’t supplied in the query string, this will return a validation error response (400 – Bad Request):
"errors": {
"name": [
"The name field is required."
]
}
Code language: plaintext (plaintext)
When the key is optional
The simplest way to check if a key was supplied is to check if the key exists:
HttpContext.Request.Query.ContainsKey("oscarWins")
Code language: C# (cs)
In some cases, you may want to use nullable types instead. If the key wasn’t supplied, its value will be null.
[HttpGet("search")]
public IActionResult Search(string name, int? oscarWins)
{
if (oscarWins.HasValue)
{
//use oscarWins to filter
}
else
{
//don't use oscarWins to filter
}
//rest of method
}
Code language: C# (cs)
Note: Don’t use non-nullable types. If the key doesn’t exist, the value will be set to default(thatType), which might match a legitimate value (like 0 for int). So that’s not a reliable way to check if a key was passed in.
Comments are closed.