Bagaimana cara membaca nilai dari querystring dengan ASP.NET Core?

135

Saya sedang membangun satu API tenang menggunakan ASP.NET Core MVC dan saya ingin menggunakan parameter querystring untuk menentukan penyaringan dan paging pada sumber daya yang mengembalikan koleksi.

Dalam hal ini, saya perlu membaca nilai yang dikirimkan dalam querystring untuk memfilter dan memilih hasil untuk dikembalikan.

Saya sudah menemukan bahwa di dalam Gettindakan pengontrol mengakses HttpContext.Request.Querymengembalikan satu IQueryCollection.

Masalahnya adalah saya tidak tahu bagaimana ini digunakan untuk mengambil nilai. Sebenarnya, saya pikir cara untuk melakukannya adalah dengan menggunakan, misalnya

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

Masalahnya adalah bahwa HttpContext.Request.Query["page"]tidak mengembalikan string, tetapi a StringValues.

Lagi pula, bagaimana cara menggunakan IQueryCollectionuntuk benar-benar membaca nilai querystring?

pengguna1620696
sumber
1
Saya menulis posting untuk hal yang sama yang dapat Anda temukan di sini: neelbhatt40.wordpress.com/2017/07/06/…
Neel

Jawaban:

134

Anda dapat menggunakan [FromQuery]untuk mengikat model tertentu ke querystring:

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

misalnya

[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
{...}
Mike_G
sumber
5
Saya pikir [FromQuery]attrib juga dapat dimatikan karena .net binding akan memeriksa semua input form dan url querystring params secara default, kecuali bahwa Anda memiliki beberapa alasan untuk membatasi sumbernya.
S.Serpooshan
12
(Name = "page") tidak perlu - itu akan mengikat ke variabel jika bernama sama
a3uge
Ini penting jika nama parameter querystring terstruktur. Misalnya 'object.propname'
Jose Capistrano
96

Anda bisa menggunakan metode ToString IQueryCollectionyang akan mengembalikan nilai yang diinginkan jika pageparameter tunggal ditentukan:

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

jika ada beberapa nilai seperti ?page=1&page=2maka hasil dari panggilan ToString adalah1,2

Tetapi seperti yang disarankan @ mike-g dalam jawabannya, Anda sebaiknya menggunakan model binding dan tidak langsung mengakses HttpContext.Request.Queryobjek.

Darin Dimitrov
sumber
6
ToString tidak perlu. Kompiler akan melemparkannya secara implisit, jika Anda menetapkan nilai kueri ke string ..
Stefan Steiger
26

ASP.NET Core akan secara otomatis mengikat form values, route valuesdan query stringsberdasarkan nama. Ini artinya Anda cukup melakukan ini:

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

MVC akan mencoba untuk mengikat data permintaan ke parameter tindakan dengan nama ... di bawah ini adalah daftar sumber data dalam urutan model mengikat melihat melalui mereka

  1. Form values: Ini adalah nilai formulir yang masuk dalam permintaan HTTP menggunakan metode POST. (termasuk permintaan POST jQuery).

  2. Route values: Himpunan nilai rute yang disediakan oleh Routing

  3. Query strings: Bagian string kueri dari URI.

Sumber: Cara kerja model mengikat


FYI, Anda juga dapat menggabungkan pendekatan otomatis dan eksplisit:

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

Anda bisa membuat objek seperti ini:

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

Dan kemudian di controller hanya membuat sesuatu seperti itu:

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

Lebih baik lagi, Anda dapat membuat model API dari:

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

untuk:

[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
sumber
Apa URL yang akan berlaku ini? Saya baru dalam hal ini jadi saya tidak bisa "mundur insinyur" ke URL. Apakah akan seperti example.com/somequery/… ?
Christian
1
@Christian jika Anda tidak mengubah konvensi apa pun, itu akan menjadi example.com/[controller[/[action[/{someid:int}?someparameter=1&someparameter2=2
LxL
19

Berikut adalah contoh kode yang saya gunakan (dengan tampilan .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

    if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
        queryVal.FirstOrDefault() == "yourValue")
    {
    }
}
Pavel
sumber
2
Upvote untuk menyertakan nama objek LENGKAP (atau pernyataan penggunaan yang benar). Membuat saya gila ketika orang-orang hanya memasukkan objectname tanpa kualifikasi penuh atau setidaknya pernyataan menggunakan. Terima kasih.
granadaCoder
11

StringValuesadalah array string . Anda bisa mendapatkan nilai string Anda dengan memberikan indeks, mis HttpContext.Request.Query["page"][0].

Constantinos G.
sumber
1
Terima kasih; inilah satu-satunya jawaban yang benar-benar menjawab pertanyaan itu. (Dalam kasus saya, saya tidak dapat menggunakan penjilidan karena saya memiliki logika yang lebih kompleks seperti "pertama coba string kueri, jika tidak ada coba sesi dan sebagainya".)
Marcel Popescu
7

IQueryCollectionmemiliki TryGetValue()di atasnya yang mengembalikan nilai dengan kunci yang diberikan. Jadi, jika Anda memiliki parameter kueri yang disebutsomeInt , Anda dapat menggunakannya seperti ini:

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

Perhatikan bahwa kecuali Anda memiliki beberapa parameter dengan nama yang sama, StringValuesjenisnya tidak menjadi masalah.

steamrolla
sumber
Untuk menambah jawaban ini, jika Anda memanggil StringValues.ToString (), Anda dapat melemparkannya langsung ke string jika itu yang Anda butuhkan.
eltiare
Pembaca masa depan: nama yang memenuhi syarat "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" Tambang saya ada di "Perakitan Microsoft.AspNetCore.Http.Features, Versi = 3.1.0.0," dan "Microsoft.Extensions.Primitive.StringValues" (milik saya ada di "Assembly Microsoft.Extensions.Primitive, Version = 3.1.2.0,")
granadaCoder
3

di .net core jika Anda ingin mengakses querystring dalam pandangan kami gunakan seperti

@Context.Request.Query["yourKey"]

jika kita berada di lokasi di mana @Context tidak tersedia, kita dapat menyuntikkannya

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

juga untuk cookie

HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]
M.Ali El-Sayed
sumber
2
Tidak perlu untuk semua kode itu. Cukup gunakan @ Context.Request.Query ["yourKey"]
Shadi Namrouti
Ya @ShadiNamrouti Anda benar dalam pandangan di mana \ @Context tersedia kita dapat menggunakannya seperti \ @ Context.Request.Query ["yourKey"] tetapi jika kita berada di controller kita perlu menyuntikkan HttpContextAccessor.HttpContext.
M.Ali El-Sayed
2

Saya punya solusi yang lebih baik untuk masalah ini,

  • permintaan adalah anggota ControllerBase kelas abstrak
  • GetSearchParams () adalah metode ekstensi yang dibuat dalam kelas pembantu di bawah ini.

var searchparams = await Request.GetSearchParams();

Saya telah membuat kelas statis dengan beberapa metode ekstensi

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

dengan cara ini Anda dapat dengan mudah mengakses semua parameter pencarian Anda. Saya harap ini akan membantu banyak pengembang :)

Shanjee
sumber
Apakah saya kehilangan sesuatu - di mana FhirException didefinisikan, di mana ruang nama yang ditemukan oleh Task <SearchParams>?
Doug Thompson - DouggyFresh
1

Beberapa komentar menyebutkan ini juga, tetapi inti net asp melakukan semua ini untuk Anda.

Jika Anda memiliki string kueri yang cocok dengan namanya, string itu akan tersedia di 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

Yordania
sumber