Como ler valores da querystring com o ASP.NET Core?

135

Estou criando uma API RESTful usando o ASP.NET Core MVC e quero usar parâmetros de querystring para especificar a filtragem e a paginação em um recurso que retorna uma coleção.

Nesse caso, preciso ler os valores passados ​​na string de consulta para filtrar e selecionar os resultados a serem retornados.

Eu já descobri que dentro da Getação do controlador acessar HttpContext.Request.Queryretorna um IQueryCollection.

O problema é que não sei como é usado para recuperar os valores. Na verdade, pensei que a maneira de fazer era usar, por exemplo,

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

O problema é que HttpContext.Request.Query["page"]não retorna uma string, mas a StringValues.

Enfim, como alguém usa o IQueryCollectionpara realmente ler os valores da string de consulta?

user1620696
fonte
1
Eu escrevi um post para o mesmo que você pode encontrar aqui: neelbhatt40.wordpress.com/2017/07/06/…
Neel

Respostas:

134

Você pode usar [FromQuery]para ligar um modelo específico à string de consulta:

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

por exemplo

[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
{...}
Mike_G
fonte
5
Eu acho que o [FromQuery]attrib também pode ser omitido, pois a ligação .net verificará todas as entradas de formulário e parâmetros de URL de consulta por padrão, exceto que você tem algum motivo para limitar sua origem.
precisa saber é o seguinte
12
(Name = "page") é desnecessário - ele será vinculado à variável se tiver o mesmo nome
a3uge
Isso é importante se o nome do parâmetro querystring estiver estruturado. Por exemplo 'object.propname'
Jose Capistrano
96

Você pode usar o método ToString no IQueryCollectionqual retornará o valor desejado se um único pageparâmetro for especificado:

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

se houver vários valores ?page=1&page=2, o resultado da chamada ToString será1,2

Mas, como @ mike-g sugeriu em sua resposta, é melhor usar a ligação de modelo e não acessar diretamente o HttpContext.Request.Queryobjeto.

Darin Dimitrov
fonte
6
O ToString não é necessário. O compilador irá lançá-lo implicitamente, se você atribuir o valor da consulta para uma cadeia ..
Stefan Steiger
26

ASP.NET Core irá ligar automaticamente form values, route valuese query stringspelo nome. Isso significa que você pode simplesmente fazer isso:

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

O MVC tentará vincular os dados da solicitação aos parâmetros de ação por nome ... abaixo está uma lista das fontes de dados na ordem em que a ligação do modelo as examina

  1. Form values: Esses são valores de formulário que vão na solicitação HTTP usando o método POST. (incluindo solicitações jQuery POST).

  2. Route values: O conjunto de valores de rota fornecidos pelo Routing

  3. Query strings: A parte da string de consulta do URI.

Fonte: Como funciona a ligação do modelo


Para sua informação, você também pode combinar as abordagens automáticas e explícitas:

[HttpGet()]
public IActionResult Get(int page
     , [FromQuery(Name = "page-size")] int pageSize)
{ ... }
spottedmahn
fonte
20

Você pode apenas criar um objeto como este:

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

E então, no controlador, faça algo assim:

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

Ainda melhor, você pode criar um modelo de API a partir de:

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

para:

[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
fonte
Para que URL isso se aplica? Eu sou novo nisso, então não posso "fazer engenharia reversa" no URL. Seria algo como example.com/somequery/… ?
Christian
1
@Christian se você não mudar nenhuma convenção, seria example.com/[controller.la/optionaction//someid:int}?someparameter=1&someparameter2=2
LxL
19

Aqui está um exemplo de código que eu usei (com uma exibição do .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

    if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
        queryVal.FirstOrDefault() == "yourValue")
    {
    }
}
Pavel
fonte
2
Voto positivo por incluir o nome do objeto CHEIO (ou a instrução using correta). Isso me deixa maluco quando as pessoas colocam apenas o nome do objeto sem nenhuma instrução totalmente qualificada ou pelo menos uma declaração de uso. Obrigado.
granadaCoder 9/03
11

StringValuesé uma matriz de strings . Você pode obter o valor da string fornecendo um índice, por exemplo HttpContext.Request.Query["page"][0].

Constantinos G.
fonte
1
Obrigado; essa foi a única resposta que realmente respondeu à pergunta. (No meu caso, eu não posso usar a ligação, porque eu tenho uma lógica mais complexa como a "primeira tentativa a string de consulta, se o que está faltando tentar a sessão e assim por diante".)
Marcel Popescu
7

IQueryCollectiontem um TryGetValue()que retorna um valor com a chave fornecida. Portanto, se você tivesse um parâmetro de consulta chamado someInt, poderia usá-lo da seguinte maneira:

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

Observe que, a menos que você tenha vários parâmetros com o mesmo nome, o StringValuestipo não é um problema.

steamrolla
fonte
Para adicionar a esta resposta, se você chamar StringValues.ToString (), poderá convertê-la diretamente em uma string, se for o que precisa.
Eltiare 19/02/19
Futuros leitores: nome completo "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" O meu estava em "Assembly Microsoft.AspNetCore.Http.Features, Version = 3.1.0.0" e "Microsoft.Extensions.Primitives.StringValues" (o meu estava em "Assembly Microsoft.Extensions.Primitives, Version = 3.1.2.0,")
granadaCoder 9/03
3

no núcleo .net, se você deseja acessar a string de consulta em nossa visão, use-a como

@Context.Request.Query["yourKey"]

se estivermos em um local onde o @Context não esteja disponível, podemos injetá-lo como

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

também para cookies

HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]
M.Ali El-Sayed
fonte
2
Não há necessidade de todo esse código. Basta usar @ Context.Request.Query ["yourKey"]
Shadi Namrouti
Sim, @ShadiNamrouti, você está certo, onde \ @Context está disponível, podemos usá-lo como \ @ Context.Request.Query ["yourKey"], mas se estivermos no controlador, precisamos injetar o HttpContextAccessor.HttpContext.
M.Ali El-Sayed
2

Eu tenho uma solução melhor para esse problema,

  • request é um membro da classe abstrata ControllerBase
  • GetSearchParams () é um método de extensão criado na classe auxiliar abaixo.

var searchparams = await Request.GetSearchParams();

Eu criei uma classe estática com poucos métodos de extensão

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;
    }
}

Dessa forma, você pode acessar facilmente todos os seus parâmetros de pesquisa. Espero que isso ajude muitos desenvolvedores :)

Shanjee
fonte
Estou faltando alguma coisa - onde FhirException está definido, em qual espaço de nome está a Tarefa <SearchParams> encontrada?
Doug Thompson - DouggyFresh 29/03
1

Alguns dos comentários mencionam isso também, mas o asp net core faz todo esse trabalho para você.

Se você tiver uma string de consulta que corresponda ao nome, ela estará disponível no controlador.

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

Jordânia
fonte