271

I'm building one RESTful API using ASP.NET Core MVC and I want to use querystring parameters to specify filtering and paging on a resource that returns a collection.

In that case, I need to read the values passed in the querystring to filter and select the results to return.

I've already found out that inside the controller Get action accessing HttpContext.Request.Query returns one IQueryCollection.

The problem is that I don't know how it is used to retrieve the values. In truth, I thought the way to do was by using, for example

string page = HttpContext.Request.Query["page"]

The problem is that HttpContext.Request.Query["page"] doesn't return a string, but a StringValues.

Anyway, how does one use the IQueryCollection to actually read the querystring values?

user1620696
  • 10,825
  • 13
  • 60
  • 81

14 Answers14

246

You can use [FromQuery] to bind a particular model to the querystring:

https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

e.g.

[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
{...}
ono2012
  • 4,967
  • 2
  • 33
  • 42
Mike_G
  • 16,237
  • 14
  • 70
  • 101
  • 12
    I think the `[FromQuery]` attrib can also be ommited as the .net binding will check all the form inputs and url querystring params by default, except that you have some reason to limit its source. – S.Serpooshan Aug 29 '18 at 10:42
  • 40
    (Name = "page") is unnecessary - it will bind to the variable if named the same – a3uge Sep 04 '18 at 13:38
  • 3
    This is important if the querystring parameter name is structured. For example 'object.propname' – Jose Capistrano May 04 '20 at 05:56
164

You could use the ToString method on IQueryCollection which will return the desired value if a single page parameter is specified:

string page = HttpContext.Request.Query["page"].ToString();

if there are multiple values like ?page=1&page=2 then the result of the ToString call will be 1,2

But as @mike-g suggested in his answer you would better use model binding and not directly accessing the HttpContext.Request.Query object.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 15
    The ToString is not necessary. The compiler will cast it implicitly, if you assign the query-value to a string.. – Stefan Steiger Apr 11 '17 at 18:30
  • 6
    Adding ToString() even dangerous. If the URL doesn't have a query string ID, the returned value would be null(https://learn.microsoft.com/en-us/dotnet/api/system.web.httprequest.querystring?view=netframework-4.8#examples ) and cause NullReference exception. – Michael Freidgeim Apr 25 '21 at 02:36
  • 1
    @MichaelFreidgeim no it's not, and no it won't, `StringValues` is a struct, it can't be null, in addition your link points to NET Framework article. – Alex from Jitbit Feb 13 '23 at 13:54
  • 1
    @AlexfromJitbit, you are right, in Asp.Net Core it returns StringValues.Empty if the key is not present. https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iquerycollection.item?view=aspnetcore-7.0#microsoft-aspnetcore-http-iquerycollection-item(system-string) – Michael Freidgeim Feb 15 '23 at 11:46
  • @Darin can you kindly check this thread. https://stackoverflow.com/questions/75846918/how-to-read-the-querystring-value-not-working – Prageeth Liyanage Mar 26 '23 at 09:52
68

ASP.NET Core will automatically bind form values, route values and query strings by name. This means you can simply do this:

[HttpGet()]
public IActionResult Get(int page)
{ ... }

MVC will try to bind request data to the action parameters by name ... below is a list of the data sources in the order that model binding looks through them

  1. Form values: These are form values that go in the HTTP request using the POST method. (including jQuery POST requests).

  2. Route values: The set of route values provided by Routing

  3. Query strings: The query string part of the URI.

Source: Model Binding in ASP.NET Core


FYI, you can also combine the automatic and explicit approaches:

[HttpGet()]
public IActionResult Get(int page
     , [FromQuery(Name = "page-size")] int pageSize)
{ ... }
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
  • 4
    While not the answer to the op's question, this is a very useful answer to those who came here for a similar reason. – Mmm Aug 04 '21 at 22:23
45

Here is a code sample I've used (with a .NET Core view):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

    if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
        queryVal.FirstOrDefault() == "yourValue")
    {
    }
}
Pierre Arnaud
  • 10,212
  • 11
  • 77
  • 108
Pavel
  • 652
  • 7
  • 10
  • 19
    Upvote for including the FULL object name (or the correct using statement). Drives me nuts when people put just the objectname with no fully qualfied or at least a using statement. Thanks. – granadaCoder Mar 09 '20 at 14:27
36

You can just create an object like this:

public class SomeQuery
{
    public string SomeParameter { get; set; }
    public int? SomeParameter2 { get; set; }
}

And then in controller just make something like that:

[HttpGet]
public IActionResult FindSomething([FromQuery] SomeQuery query)
{
    // Your implementation goes here..
}

Even better, you can create API model from:

[HttpGet]
public IActionResult GetSomething([FromRoute] int someId, [FromQuery] SomeQuery query)

to:

[HttpGet]
public IActionResult GetSomething(ApiModel model)

public class ApiModel
{
    [FromRoute]
    public int SomeId { get; set; }
    [FromQuery]
    public string SomeParameter { get; set; }
    [FromQuery]
    public int? SomeParameter2 { get; set; }
}
Mariusz
  • 598
  • 7
  • 14
  • What’s a URL that this would apply to? I’m new to this so I can’t “backwards engineer” to the URL. Would it be something like http://example.com/somequery/findquery?someparameter1=1&someparameter2=2 ? – Christian Aug 11 '19 at 14:59
  • 1
    @Christian if you don't change any convention, it would be example.com/[controller]/[action]/{someid:int}?someparameter=1&someparameter2=2 – LxL Aug 14 '19 at 18:16
24

StringValues is an array of strings. You can get your string value by providing an index, e.g. HttpContext.Request.Query["page"][0].

MD. Khairul Basar
  • 4,976
  • 14
  • 41
  • 59
Constantinos G.
  • 305
  • 3
  • 9
  • 3
    Thank you; this was the only response that actually answered the question. (In my case, I can't use binding because I have a more complex logic like "first try the query string, if that's missing try the session and so on".) – Marcel Popescu Dec 23 '18 at 17:56
  • Perfect answer after searching evenrywhere – Hardik Masalawala Oct 31 '22 at 13:53
11

IQueryCollection has a TryGetValue() on it that returns a value with the given key. So, if you had a query parameter called someInt, you could use it like so:

var queryString = httpContext.Request.Query;
StringValues someInt;
queryString.TryGetValue("someInt", out someInt);
var daRealInt = int.Parse(someInt);

Notice that unless you have multiple parameters of the same name, the StringValues type is not an issue.

steamrolla
  • 2,373
  • 1
  • 29
  • 39
  • To add to this answer, if you call StringValues.ToString() you can cast it directly to a string if that's what you need. – eltiare Feb 19 '18 at 19:02
  • Future readers: fully qualified name "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" Mine was in "Assembly Microsoft.AspNetCore.Http.Features, Version=3.1.0.0," and "Microsoft.Extensions.Primitives.StringValues" (mine was in "Assembly Microsoft.Extensions.Primitives, Version=3.1.2.0,") – granadaCoder Mar 09 '20 at 14:28
11

in .net core if you want to access querystring in our view use it like

@Context.Request.Query["yourKey"]

if we are in location where @Context is not avilable we can inject it like

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@if (HttpContextAccessor.HttpContext.Request.Query.Keys.Contains("yourKey"))
{
      <text>do something </text>
}

also for cookies

HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]
M.Ali El-Sayed
  • 1,608
  • 20
  • 23
  • 2
    No need for all that code. Just use @Context.Request.Query["yourKey"] – Shadi Alnamrouti Jan 14 '19 at 17:56
  • Yes @ShadiNamrouti you are right in view where \@Context is avilable we can use it like \@Context.Request.Query["yourKey"] but if we are in controller we need to inject the HttpContextAccessor.HttpContext. – M.Ali El-Sayed Jun 30 '19 at 10:23
8

Maybe it helps. For get query string parameter in view

View:

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@{ Context.Request.Query["uid"]}

Startup.cs ConfigureServices :

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Sinan Dogan
  • 105
  • 1
  • 1
3

I have a better solution for this problem,

  • request is a member of abstract class ControllerBase
  • GetSearchParams() is an extension method created in bellow helper class.

var searchparams = await Request.GetSearchParams();

I have created a static class with few extension methods

public static class HttpRequestExtension
{
  public static async Task<SearchParams> GetSearchParams(this HttpRequest request)
        {
            var parameters = await request.TupledParameters();

            try
            {
                for (var i = 0; i < parameters.Count; i++)
                {
                    if (parameters[i].Item1 == "_count" && parameters[i].Item2 == "0")
                    {
                        parameters[i] = new Tuple<string, string>("_summary", "count");
                    }
                }
                var searchCommand = SearchParams.FromUriParamList(parameters);
                return searchCommand;
            }
            catch (FormatException formatException)
            {
                throw new FhirException(formatException.Message, OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Fatal, HttpStatusCode.BadRequest);
            }
        }



public static async Task<List<Tuple<string, string>>> TupledParameters(this HttpRequest request)
{
        var list = new List<Tuple<string, string>>();


        var query = request.Query;
        foreach (var pair in query)
        {
            list.Add(new Tuple<string, string>(pair.Key, pair.Value));
        }

        if (!request.HasFormContentType)
        {
            return list;
        }
        var getContent = await request.ReadFormAsync();

        if (getContent == null)
        {
            return list;
        }
        foreach (var key in getContent.Keys)
        {
            if (!getContent.TryGetValue(key, out StringValues values))
            {
                continue;
            }
            foreach (var value in values)
            {
                list.Add(new Tuple<string, string>(key, value));
            }
        }
        return list;
    }
}

in this way you can easily access all your search parameters. I hope this will help many developers :)

Shanjee
  • 491
  • 5
  • 16
2

Some of the comments mention this as well, but asp net core does all this work for you.

If you have a query string that matches the name it will be available in the controller.

https://myapi/some-endpoint/123?someQueryString=YayThisWorks

[HttpPost]
[Route("some-endpoint/{someValue}")]
public IActionResult SomeEndpointMethod(int someValue, string someQueryString)
    {
        Debug.WriteLine(someValue);
        Debug.WriteLine(someQueryString);
        return Ok();
    }

Ouputs:

123

YayThisWorks

Jordan Ryder
  • 2,336
  • 1
  • 24
  • 29
2
  1. Startup.cs add this service services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  2. Your view add inject @inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
  3. get your value

Code

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@{
    var id = HttpContextAccessor.HttpContext.Request.RouteValues["id"];

    if (id != null)
    {
        // parameter exist in your URL 
    }
}
Zanyar Jalal
  • 1,407
  • 12
  • 29
1

In case you want to access QueryString inside of an asp.net core view you can do it like this:

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor

@if (Context.Request.Query.Keys.Any())
{
    <button>--ClearFilters--</button>
}
CodingYourLife
  • 7,172
  • 5
  • 55
  • 69
0

we usually can fetch data from routing in 3 way: 1.query string 2.query params 3.hybrid

I describe query string:

exp:

[HttpGet("Home/routing")]
public IActionResult privacy(String name)
{
return ViewModel:name
}

to pass name as querystring:

url:port/Home/routing?name=Alex