Как читать значения из строки запроса с помощью ASP.NET Core?


137

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

В этом случае мне нужно прочитать значения, переданные в строке запроса, для фильтрации и выбрать результаты для возврата.

Я уже выяснил, что внутри Getдействия контроллера обращение к нему HttpContext.Request.Queryвозвращает IQueryCollection.

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

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

Проблема в том, что HttpContext.Request.Query["page"]возвращает не строку, а StringValues.

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


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

Ответы:


137

Вы можете использовать [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 по умолчанию, за исключением того, что у вас есть причина ограничить его источник.
— С.Серпушан

12
(Name = "page") не требуется - он будет привязан к переменной, если будет назван одинаково
— a3uge

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

99

Вы можете использовать метод ToString, IQueryCollectionкоторый вернет желаемое значение, если pageуказан единственный параметр:

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

если есть несколько значений, например, ?page=1&page=2тогда результат вызова ToString будет1,2

Но, как предположил @ mike-g в своем ответе, вам лучше использовать привязку модели, а не напрямую обращаться к HttpContext.Request.Queryобъекту.


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

27

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: Набор значений маршрута, предоставляемых Routing.

  3. Query strings: Часть строки запроса URI.

Источник: Как работает привязка модели


К вашему сведению, вы также можете комбинировать автоматический и явный подходы:

[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/[controller
— provided/[actionpting/{someid:int}?someparameter=1&someparameter2=2

19

Вот пример кода, который я использовал (с представлением .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

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

2
Проголосуйте за включение ПОЛНОГО имени объекта (или правильного оператора using). Меня сводит с ума, когда люди помещают только имя объекта без полностью квалифицированного или, по крайней мере, оператора using. Спасибо.
— 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, Version = 3.1.0.0» и «Microsoft.Extensions.Primitives.StringValues» (мой был в «Сборке Microsoft.Extensions.Primitives, Version = 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>
}

также для файлов cookie

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

2
Нет необходимости во всем этом коде. Просто используйте @ Context.Request.Query ["yourKey"]
— Шади Намрути

Да, @ShadiNamrouti, вы правы, когда доступен \ @Context, мы можем использовать его как \ @ Context.Request.Query ["yourKey"], но если мы находимся в контроллере, нам нужно ввести HttpContextAccessor.HttpContext.
— M.Ali El-Sayed

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, в каком пространстве имен находится Task <SearchParams>?
— Дуг Томпсон - DouggyFresh

1

В некоторых комментариях это тоже упоминается, но ядро ​​asp net делает всю эту работу за вас.

Если у вас есть строка запроса, соответствующая имени, она будет доступна в контроллере.

https: //? MyAPI / некоторые конечная точка / 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.