Come leggere i valori dalla stringa di query con ASP.NET Core?


135

Sto creando un'API RESTful utilizzando ASP.NET Core MVC e desidero utilizzare i parametri querystring per specificare il filtro e il paging su una risorsa che restituisce una raccolta.

In tal caso, devo leggere i valori passati nella stringa di query per filtrare e selezionare i risultati da restituire.

Ho già scoperto che all'interno Getdell'azione del controller l' accesso HttpContext.Request.Queryrestituisce uno IQueryCollection.

Il problema è che non so come viene utilizzato per recuperare i valori. In verità, ho pensato che il modo di fare fosse usare, per esempio

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

Il problema è che HttpContext.Request.Query["page"]non restituisce una stringa, ma a StringValues.

Ad ogni modo, come si usa IQueryCollectionper leggere effettivamente i valori di querystring?


1
Ho scritto un post per lo stesso che puoi trovare qui: neelbhatt40.wordpress.com/2017/07/06/…
Neel

Risposte:


135

È possibile utilizzare [FromQuery]per associare un modello particolare alla stringa di query:

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

per esempio

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

5
Penso che l' [FromQuery]attributo possa anche essere considerato come l'associazione .net controllerà tutti gli input del modulo e i parametri di query di url per impostazione predefinita, tranne per il fatto che hai qualche motivo per limitarne l'origine.
S. Serpooshan,

12
(Nome = "pagina") non è necessario - si legherà alla variabile se denominata uguale
a3uge

Questo è importante se il nome del parametro querystring è strutturato. Ad esempio "object.propname"
Jose Capistrano

96

È possibile utilizzare il metodo ToString su IQueryCollectioncui restituirà il valore desiderato se pageviene specificato un singolo parametro:

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

se ci sono più valori come ?page=1&page=2allora il risultato della chiamata ToString sarà1,2

Ma come suggerito da @ mike-g nella sua risposta, faresti meglio a utilizzare il binding del modello e non accedere direttamente HttpContext.Request.Queryall'oggetto.


6
ToString non è necessario. Il compilatore lo lancerà implicitamente, se si assegna il valore della query a una stringa ..
Stefan Steiger

26

ASP.NET Core automaticamente legare form values, route valuese query stringsper nome. Questo significa che puoi semplicemente farlo:

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

MVC tenterà di associare i dati della richiesta ai parametri dell'azione per nome ... di seguito è riportato un elenco delle origini dati nell'ordine in cui il binding del modello li osserva

  1. Form values: Si tratta di valori di modulo che vanno nella richiesta HTTP utilizzando il metodo POST. (comprese le richieste POST jQuery).

  2. Route values: Set di valori di route forniti da Routing

  3. Query strings: La parte della stringa di query dell'URI.

Fonte: come funziona l'associazione dei modelli


Cordiali saluti, è anche possibile combinare gli approcci automatici ed espliciti:

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

20

Puoi semplicemente creare un oggetto come questo:

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

E poi nel controller basta fare qualcosa del genere:

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

Ancora meglio, puoi creare un modello API da:

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

per:

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

Cos'è un URL a cui questo si applicherebbe? Sono nuovo di questo, quindi non posso "retroingegnerizzare" l'URL. Sarebbe qualcosa come example.com/somequery/… ?
Christian,

1
@Christian se non cambi alcuna convenzione, sarebbe example.com/[controller×/[action×/{someid:int}?someparameter=1&someparameter2=2
LxL

19

Ecco un esempio di codice che ho usato (con una vista .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

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

2
Upgrade per l'inclusione del nome oggetto FULL (o dell'istruzione using corretta). Mi fa impazzire quando le persone mettono solo il nome oggetto senza alcuna istruzione completa o almeno un'istruzione using. Grazie.
granadaCoder

11

StringValuesè una matrice di stringhe . È possibile ottenere il valore della stringa fornendo un indice, ad es HttpContext.Request.Query["page"][0].


1
Grazie; questa è stata l'unica risposta che ha effettivamente risposto alla domanda. (Nel mio caso, non posso usare l'associazione perché ho una logica più complessa come "prima prova la stringa di query, se manca prova la sessione e così via".)
Marcel Popescu il

7

IQueryCollectionha un TryGetValue()sopra che restituisce un valore con la chiave data. Quindi, se avessi un parametro di query chiamato someInt, potresti usarlo in questo modo:

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

Si noti che a meno che non si disponga di più parametri con lo stesso nome, il StringValuestipo non è un problema.


Per aggiungere a questa risposta, se chiami StringValues.ToString () puoi lanciarlo direttamente su una stringa se è quello che ti serve.
eltiare,

Lettori futuri: nome completo "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" Il mio era in "Assembly Microsoft.AspNetCore.Http.Features, Version = 3.1.0.0" e "Microsoft.Extensions.Primitives.StringValues" (il mio era in "Assembly Microsoft.Extensions.Primitives, Version = 3.1.2.0,")
granadaCoder

3

in .net core se vuoi accedere a querystring a nostro avviso usalo come

@Context.Request.Query["yourKey"]

se ci troviamo in un luogo in cui @Context non è disponibile, possiamo iniettarlo come

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

anche per i cookie

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

2
Non c'è bisogno di tutto quel codice. Basta usare @ Context.Request.Query ["yourKey"]
Shadi Namrouti

Sì @ShadiNamrouti hai ragione quando è disponibile \ @Context, possiamo usarlo come \ @ Context.Request.Query ["yourKey"] ma se siamo nel controller dobbiamo iniettare HttpContextAccessor.HttpContext.
M. Ali El-Sayed,

2

Ho una soluzione migliore per questo problema,

  • richiesta è un membro della classe astratta ControllerBase
  • GetSearchParams () è un metodo di estensione creato nella seguente classe di supporto.

var searchparams = await Request.GetSearchParams();

Ho creato una classe statica con alcuni metodi di estensione

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 questo modo puoi accedere facilmente a tutti i tuoi parametri di ricerca. Spero che questo possa aiutare molti sviluppatori :)


Mi sto perdendo qualcosa: dove è definito FhirException, in quale spazio dei nomi è presente l'attività <SearchParams>?
Doug Thompson - DouggyFresh

1

Alcuni dei commenti menzionano anche questo, ma asp net core fa tutto questo lavoro per te.

Se si dispone di una stringa di query che corrisponde al nome, sarà disponibile nel 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();
    }

USCITE:

123

YayThisWorks

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.