Как читать значения из строки запроса с помощью 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.