Comment lire les valeurs de la chaîne de requête avec ASP.NET Core?


135

Je construis une API RESTful à l'aide d'ASP.NET Core MVC et je souhaite utiliser des paramètres de chaîne de requête pour spécifier le filtrage et la pagination sur une ressource qui renvoie une collection.

Dans ce cas, je dois lire les valeurs passées dans la chaîne de requête pour filtrer et sélectionner les résultats à renvoyer.

J'ai déjà découvert qu'à l'intérieur de l' Getaction du contrôleur , l'accès en HttpContext.Request.Queryrenvoie un IQueryCollection.

Le problème est que je ne sais pas comment il est utilisé pour récupérer les valeurs. En vérité, je pensais que la façon de faire était d'utiliser, par exemple

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

Le problème est que HttpContext.Request.Query["page"]cela ne renvoie pas de chaîne, mais un fichier StringValues.

Quoi qu'il en soit, comment utiliser IQueryCollectionpour lire réellement les valeurs de la chaîne de requête?


1
J'ai écrit un post pour le même que vous pouvez trouver ici: neelbhatt40.wordpress.com/2017/07/06/…
Neel

Réponses:


135

Vous pouvez utiliser [FromQuery]pour lier un modèle particulier à la chaîne de requête:

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

par exemple

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

5
Je pense que l' [FromQuery]attribut peut également être omis car la liaison .net vérifiera toutes les entrées de formulaire et tous les paramètres de chaîne de requête d'url par défaut, sauf que vous avez des raisons de limiter sa source.
S.Serpooshan

12
(Name = "page") est inutile - il se liera à la variable si le nom est le même
a3uge

Ceci est important si le nom du paramètre de chaîne de requête est structuré. Par exemple 'object.propname'
Jose Capistrano

96

Vous pouvez utiliser la méthode ToString sur IQueryCollection laquelle retournera la valeur souhaitée si un seul pageparamètre est spécifié:

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

s'il y a plusieurs valeurs comme ?page=1&page=2alors le résultat de l'appel ToString sera1,2

Mais comme @ mike-g l'a suggéré dans sa réponse, vous feriez mieux d'utiliser la liaison de modèle et de ne pas accéder directement à l' HttpContext.Request.Queryobjet.


6
Le ToString n'est pas nécessaire. Le compilateur le castera implicitement, si vous attribuez la valeur de la requête à une chaîne.
Stefan Steiger

26

ASP.NET de base se liera automatiquement form values, route valueset query stringspar son nom. Cela signifie que vous pouvez simplement faire ceci:

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

MVC essaiera de lier les données de la demande aux paramètres d'action par nom ... ci-dessous est une liste des sources de données dans l'ordre dans lequel la liaison de modèle les examine

  1. Form values: Ce sont des valeurs de formulaire qui vont dans la requête HTTP à l'aide de la méthode POST. (y compris les requêtes jQuery POST).

  2. Route values: L'ensemble des valeurs d'itinéraire fourni par le routage

  3. Query strings: La chaîne de requête partie de l'URI.

Source: Fonctionnement de la liaison de modèle


Pour info, vous pouvez également combiner les approches automatiques et explicites:

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

20

Vous pouvez simplement créer un objet comme celui-ci:

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

Et puis dans le contrôleur, faites quelque chose comme ça:

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

Mieux encore, vous pouvez créer un modèle d'API à partir de:

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

à:

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

À quelle URL cela s'appliquerait-il? Je suis nouveau dans ce domaine, donc je ne peux pas "rétroconcevoir" l'URL. Serait-ce quelque chose comme example.com/somequery/... ?
Christian

1
@Christian si vous ne modifiez aucune convention, ce serait example.com/[controller
Often

19

Voici un exemple de code que j'ai utilisé (avec une vue .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

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

2
Vote pour l'inclusion du nom d'objet FULL (ou de l'instruction using correcte). Cela me rend fou quand les gens mettent juste le nom de l'objet sans aucune instruction entièrement qualifiée ou au moins une instruction using. Merci.
granadaCoder

11

StringValuesest un tableau de chaînes . Vous pouvez obtenir la valeur de votre chaîne en fournissant un index, par exemple HttpContext.Request.Query["page"][0].


1
Je vous remercie; c'était la seule réponse qui répondait réellement à la question. (Dans mon cas, je ne peux pas utiliser de liaison parce que j'ai une logique plus complexe comme "essayez d'abord la chaîne de requête, si elle manque, essayez la session et ainsi de suite".)
Marcel Popescu

7

IQueryCollectiona un TryGetValue()dessus qui renvoie une valeur avec la clé donnée. Donc, si vous avez appelé un paramètre de requête someInt, vous pouvez l'utiliser comme ceci:

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

Notez qu'à moins que vous n'ayez plusieurs paramètres du même nom, le StringValuestype n'est pas un problème.


Pour ajouter à cette réponse, si vous appelez StringValues.ToString (), vous pouvez le convertir directement en chaîne si c'est ce dont vous avez besoin.
eltiare

Futurs lecteurs: nom complet "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" Le mien était dans "Assembly Microsoft.AspNetCore.Http.Features, Version = 3.1.0.0" et "Microsoft.Extensions.Primitives.StringValues" (le mien était dans "Assembly Microsoft.Extensions.Primitives, Version = 3.1.2.0,")
granadaCoder

3

dans .net core si vous souhaitez accéder à la chaîne de requête dans notre vue, utilisez-le comme

@Context.Request.Query["yourKey"]

si nous sommes dans un endroit où @Context n'est pas disponible, nous pouvons l'injecter comme

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

aussi pour les cookies

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

2
Pas besoin de tout ce code. Utilisez simplement @ Context.Request.Query ["yourKey"]
Shadi Namrouti

Oui @ShadiNamrouti vous avez raison dans la vue où \ @Context est disponible, nous pouvons l'utiliser comme \ @ Context.Request.Query ["yourKey"] mais si nous sommes dans le contrôleur, nous devons injecter le HttpContextAccessor.HttpContext.
M.Ali El-Sayed

2

J'ai une meilleure solution pour ce problème,

  • request est membre de la classe abstraite ControllerBase
  • GetSearchParams () est une méthode d'extension créée dans la classe d'assistance ci-dessous.

var searchparams = await Request.GetSearchParams();

J'ai créé une classe statique avec quelques méthodes d'extension

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 cette façon, vous pouvez facilement accéder à tous vos paramètres de recherche. J'espère que cela aidera de nombreux développeurs :)


Est-ce que je manque quelque chose - où FhirException est-il défini, dans quel espace de nom se trouve la tâche <SearchParams>?
Doug Thompson - DouggyFresh

1

Certains commentaires le mentionnent également, mais asp net core fait tout ce travail pour vous.

Si vous avez une chaîne de requête qui correspond au nom, elle sera disponible dans le contrôleur.

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

Sorties:

123

YayThisWorks

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.