Як читати значення з запиту за допомогою 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.