¿Cómo leer valores de la cadena de consulta con ASP.NET Core?


135

Estoy creando una API RESTful usando ASP.NET Core MVC y quiero usar parámetros de cadena de consulta para especificar el filtrado y la paginación en un recurso que devuelve una colección.

En ese caso, necesito leer los valores pasados ​​en la cadena de consulta para filtrar y seleccionar los resultados para devolver.

Ya descubrí que dentro de la Getacción del controlador , el acceso HttpContext.Request.Querydevuelve uno IQueryCollection.

El problema es que no sé cómo se usa para recuperar los valores. En verdad, pensé que la forma de hacerlo era usando, por ejemplo

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

El problema es que HttpContext.Request.Query["page"]no devuelve una cadena, sino a StringValues.

De todos modos, ¿cómo se usa uno IQueryCollectionpara leer realmente los valores de la cadena de consulta?


1
Escribí una publicación para lo mismo que puedes encontrar aquí: neelbhatt40.wordpress.com/2017/07/06/…
Neel

Respuestas:


134

Puede usar [FromQuery]para vincular un modelo particular a la cadena de consulta:

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

p.ej

[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
{...}

55
Creo que el [FromQuery]atributo también se puede omitir, ya que el enlace .net verificará todas las entradas de formulario y los parámetros de cadena de consulta de URL de forma predeterminada, excepto que tiene alguna razón para limitar su fuente.
S.Serpooshan

12
(Nombre = "página") es innecesario: se unirá a la variable si se llama igual
a3uge

Esto es importante si el nombre del parámetro querystring está estructurado. Por ejemplo 'object.propname'
Jose Capistrano

96

Puede usar el método ToString en el IQueryCollectionque devolverá el valor deseado si pagese especifica un único parámetro:

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

si hay varios valores como ?page=1&page=2entonces, el resultado de la llamada ToString será1,2

Pero como sugirió @ mike-g en su respuesta, sería mejor usar el enlace de modelo y no acceder directamente al HttpContext.Request.Queryobjeto.


66
El ToString no es necesario. El compilador lo lanzará implícitamente, si asigna el valor de consulta a una cadena ..
Stefan Steiger

26

ASP.NET Core se unirá de forma automática form values, route valuesy query stringspor su nombre. Esto significa que simplemente puede hacer esto:

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

MVC intentará vincular los datos de la solicitud a los parámetros de acción por nombre ... a continuación hay una lista de las fuentes de datos en el orden en que el enlace del modelo los revisa

  1. Form values: Estos son valores de formulario que van en la solicitud HTTP utilizando el método POST. (incluidas las solicitudes jQuery POST).

  2. Route values: El conjunto de valores de ruta proporcionados por Enrutamiento

  3. Query strings: La parte de la cadena de consulta del URI.

Fuente: Cómo funciona el enlace de modelos


Para su información, también puede combinar los enfoques automático y explícito:

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

20

Simplemente puede crear un objeto como este:

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

Y luego en el controlador solo haz algo así:

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

Aún mejor, puede crear un modelo API a partir de:

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

a:

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

¿A qué URL se aplicaría esto? Soy nuevo en esto, así que no puedo "hacer ingeniería inversa" a la URL. ¿Sería algo así como example.com/somequery/… ?
Christian

1
@Christian si no cambia ninguna convención, sería example.com/[controllerfont>/[actionfont>/{someid:int}?someparameter=1&someparameter2=2
LxL

19

Aquí hay una muestra de código que he usado (con una vista de .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

    if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
        queryVal.FirstOrDefault() == "yourValue")
    {
    }
}

2
Voto a favor para incluir el nombre de objeto COMPLETO (o la instrucción de uso correcta). Me vuelve loco cuando la gente pone solo el nombre del objeto sin una declaración completamente calificada o al menos una declaración de uso. Gracias.
granadaCoder

11

StringValueses una matriz de cadenas . Puede obtener su valor de cadena proporcionando un índice, por ejemplo HttpContext.Request.Query["page"][0].


1
Gracias; Esta fue la única respuesta que realmente respondió la pregunta. (En mi caso, no puedo usar el enlace porque tengo una lógica más compleja como "primero prueba la cadena de consulta, si falta, prueba la sesión, etc.")
Marcel Popescu

7

IQueryCollectiontiene un TryGetValue()valor que devuelve un valor con la clave dada. Entonces, si tuviera un parámetro de consulta llamado someInt, podría usarlo así:

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

Tenga en cuenta que a menos que tenga varios parámetros del mismo nombre, el StringValuestipo no es un problema.


Para agregar a esta respuesta, si llama a StringValues.ToString (), puede convertirlo directamente en una cadena si eso es lo que necesita.
eltiare

Lectores futuros: nombre completo "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" El mío estaba en "Assembly Microsoft.AspNetCore.Http.Features, Version = 3.1.0.0" y "Microsoft.Extensions.Primitives.StringValues" (el mío estaba en "Assembly Microsoft.Extensions.Primitives, Version = 3.1.2.0,")
granadaCoder

3

en .net core si desea acceder a la cadena de consulta en nuestra vista, úsela como

@Context.Request.Query["yourKey"]

si estamos en una ubicación donde @Context no está disponible, podemos inyectarlo como

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

también para galletas

HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]

2
No hay necesidad de todo ese código. Simplemente use @ Context.Request.Query ["yourKey"]
Shadi Namrouti

Sí, @ShadiNamrouti tiene la vista correcta donde \ @Context está disponible, podemos usarlo como \ @ Context.Request.Query ["yourKey"] pero si estamos en el controlador necesitamos inyectar el HttpContextAccessor.HttpContext.
M.Ali El-Sayed

2

Tengo una mejor solución para este problema,

  • request es miembro de la clase abstracta ControllerBase
  • GetSearchParams () es un método de extensión creado en la siguiente clase de ayuda.

var searchparams = await Request.GetSearchParams();

He creado una clase estática con pocos métodos de extensión.

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

De esta manera puede acceder fácilmente a todos sus parámetros de búsqueda. Espero que esto ayude a muchos desarrolladores :)


Me falta algo: ¿dónde se define FhirException, en qué espacio de nombre se encuentra la Tarea <SearchParams>?
Doug Thompson - DouggyFresh

1

Algunos de los comentarios mencionan esto también, pero asp net core hace todo este trabajo por usted.

Si tiene una cadena de consulta que coincide con el nombre, estará disponible en el 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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.