Як читати значення з запиту за допомогою ASP.NET Core?


135

Я будую один RESTful API за допомогою ASP.NET Core MVC, і я хочу використовувати параметри запитів для визначення фільтрації та пейджингу на ресурсі, який повертає колекцію.

У такому випадку мені потрібно прочитати значення, передані в рядку запитів, щоб відфільтрувати та вибрати результати для повернення.

Я вже з'ясував, що всередині Getдії контролера доступ до нього HttpContext.Request.Queryповертає IQueryCollection.

Проблема полягає в тому, що я не знаю, як це використовується для отримання значень. По правді кажучи, я думав, що це зробити, наприклад, використовуючи

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

Проблема полягає в тому, HttpContext.Request.Query["page"]що не повертає рядок, а a StringValues.

У будь-якому випадку, як можна використовувати значення IQueryCollectionдля фактичного читання значень запиту?


1
Я написав пост для того самого, який ви можете знайти тут: neelbhatt40.wordpress.com/2017/07/06/…
— Neel

Відповіді:


134

Ви можете використовувати [FromQuery]для прив’язки певної моделі до рядка запитів:

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

напр

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

5
Я думаю, що [FromQuery]attrib також може бути вимкнено, оскільки прив'язка .net перевірятиме всі параметри форми та параметри URL-адреси запиту за замовчуванням, за винятком того, що у вас є якісь причини обмежити його джерело.
— S.Serpooshan

12
(Name = "сторінка") непотрібна - вона буде прив'язуватися до змінної, якщо вона буде названа однаково
— a3uge

Це важливо, якщо структура параметра запиту структурована. Наприклад, 'object.propname'
— Хосе Капістрано

96

Ви можете скористатися методом ToString, за IQueryCollectionяким повернеться бажане значення, якщо pageвказано один параметр:

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

якщо є декілька значень, як-от ?page=1&page=2тоді результат дзвінка ToString буде1,2

Але, як @ mike-g запропонував у своїй відповіді, вам краще використовувати прив’язку моделі та не мати прямого доступу до HttpContext.Request.Queryоб'єкта.


6
ToString не потрібен. Компілятор передасть це неявно, якщо призначити значення запиту рядку ..
— Стефан Штайгер

26

ASP.NET ядро буде автоматично зв'язуватися form values, route valuesі query stringsпо імені. Це означає, що ви можете просто зробити це:

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

MVC спробує прив’язати дані запиту до параметрів дії за назвою ... нижче - перелік джерел даних у тому порядку, як їх переглядає прив'язка моделі

  1. Form values: Це значення форми, які надходять у HTTP-запиті за допомогою методу POST. (включаючи JQuery POST-запити).

  2. Route values: Набір значень маршруту, наданих маршрутизацією

  3. Query strings: Частина рядка запиту URI.

Джерело: Як працює прив'язка моделі


FYI, ви також можете комбінувати автоматичний та явний підходи:

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

20

Ви можете просто створити такий об’єкт:

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

А потім у контролері просто зробіть щось подібне:

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

Ще краще, ви можете створити модель API з:

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

Що таке URL-адреса, до якої це стосується? Я новачок у цьому, тому я не можу “назад інженеру” до URL. Це було б щось на зразок example.com/somequery/… ?
— Крістіан

1
@Christian, якщо ви не зміните будь-якої конвенції, це буде example.com/
— evidencecontrollerSense/ evidenceactionSense/{someid:int}?someparameter=

19

Ось зразок коду, який я використав (із переглядом .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

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

2
Оновлення для включення ПОВНОГО імені об'єкта (або правильного використання оператора). Наводить мене на гайки, коли люди ставлять просто ім'я об'єкта без повністю кваліфікованого або принаймні використовуючого оператора. Дякую.
— granadaCoder

11

StringValues- це масив рядків . Ви можете отримати значення рядка, вказавши індекс, наприклад HttpContext.Request.Query["page"][0].


1
Дякую; це була єдина відповідь, яка насправді відповіла на питання. (У моєму випадку я не можу використовувати прив'язку, оскільки в мене є більш складна логіка, наприклад "спершу спробуйте рядок запиту, якщо цього немає, спробуйте сеанс і так далі".)
— Марсель Попеску

7

IQueryCollectionмає TryGetValue()на ньому, що повертає значення за допомогою даного ключа. Отже, якщо у вас був викликаний параметр запиту someInt, ви можете використовувати його так:

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

Зауважте, що якщо у вас є кілька параметрів одного і того ж імені, StringValuesтип не є проблемою.


Щоб додати цю відповідь, якщо ви зателефонуєте StringValues.ToString (), ви можете передати її безпосередньо до рядка, якщо це те, що вам потрібно.
— eltiare

Майбутні читачі: повноцінне ім’я "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" Шахта була в "Асамблеї Microsoft.AspNetCore.Http.Features, версія = 3.1.0.0" та "Microsoft.Extensions.Primitive.StringValues" (моя була в "Асамблеї Microsoft.Extensions.Primitive, версія = 3.1.2.0")
— granadaCoder

3

в ядро ​​.net, якщо ви хочете отримати доступ до запиту рядків, на наш погляд, використовуйте його як

@Context.Request.Query["yourKey"]

якщо ми знаходимось у місці, де @Context не доступний, ми можемо вводити його так, як

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

також для печива

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

2
Не потрібно всього цього коду. Просто використовуйте @ Context.Request.Query ["yourKey"]
— Shadi Namrouti

Так @ShadiNamrouti ви праві, зважаючи на те, де \ @Context є доступним, ми можемо використовувати його як \ @ Context.Request.Query ["yourKey"], але якщо ми в контролері, нам потрібно ввести HttpContextAccessor.HttpContext.
— М.Алі Ель-Саєд

2

У мене є краще рішення цієї проблеми,

  • запит є членом абстрактного класу ControllerBase
  • GetSearchParams () - метод розширення, створений в нижньому класі помічників.

var searchparams = await Request.GetSearchParams();

Я створив статичний клас з кількома методами розширення

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

таким чином ви можете легко отримати доступ до всіх своїх параметрів пошуку. Сподіваюся, це допоможе багатьом розробникам :)


Я щось пропускаю - де визначено FhirException, у якому просторі імен знайдено завдання <SearchParams>?
— Дуг Томпсон - DouggyFresh

1

Деякі з коментарів згадують і про це, але ядро ​​asp net робить це все для вас.

Якщо у вас є рядок запиту, яка відповідає імені, вона буде доступна в контролері.

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

Виходи:

123

YayThisWorks

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.