Передача массива методу действия веб-API asp net core HttpGet

Я пытаюсь отправить массив целых чисел в свой метод действия, код выглядит так:

[HttpGet]
    public async Task<IActionResult> ServicesByCategoryIds([FromQuery] int[] ids)
    {
        var services = await _accountsUow.GetServiceProfilesByCategoryIdsAsync(ids);
        return Ok(services);
    }

Называю метод так: https: // localhost: 44343 / api / accounts / servicesbycategoryids? ids = 1 & ids = 2

но всегда получаю пустой массив, когда я вызываю этот метод, даже если я передаю идентификаторы в строке запроса. Я использую .net core 2.1.

все, что я гуглил, предполагает, что это действительно так. . . Что-то мне здесь не хватает?

Спасибо!

Отвечает ли это на ваш вопрос? Передать массив целых чисел в веб-API ASP.NET?

Michael Freidgeim 25.10.2020 21:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
1
16 006
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Я создаю новый класс веб-API с одним действием.

[Produces("application/json")]
[Route("api/accounts")]
public class AccountsController : Controller
{
    [HttpGet]
    [Route("servicesbycategoryids")]
    public IActionResult ServicesByCategoryIds([FromQuery] int[] ids)
    {
        return Ok();
    }
}

Затем используйте тот же URL-адрес, что и ваш:

http: // localhost: 2443 / api / accounts / servicesbycategoryids? ids = 1 & ids = 2

Это работает.

Ответ принят как подходящий

Ошибка привязки для параметра Array - это известная проблема в Asp.Net Core 2.1, которая была записана как Массив или список в строке запроса не анализируются # 7712.

В качестве временного решения вы можете установить FromQuery Name Property, как показано ниже:

        [HttpGet()]
    [Route("ServicesByCategoryIds")]
    public async Task<IActionResult> ServicesByCategoryIds([FromQuery(Name = "ids")]int[] ids)
    {            
        return Ok();
    }

также, похоже, работает, когда я удаляю ApiControllerAttribute, как было предложено в обсуждении, которое вы связали.

zoran djipanov 13.07.2018 10:51

Очень помогает !! Спасибо

Perfect28 18.09.2018 11:32

Рекомендуем использовать новые ответы от yshehab или Plamen Yovchev ниже

iGanja 25.03.2021 21:33

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

Ваша конечная точка может выглядеть так: / api / accounts / servicesbycategoryids / (1,2)

public class ArrayModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        // Our binder works only on enumerable types
        if (!bindingContext.ModelMetadata.IsEnumerableType)
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        // Get the inputted value through the value provider
        var value = bindingContext.ValueProvider
            .GetValue(bindingContext.ModelName).ToString();

        // If that value is null or whitespace, we return null
        if (string.IsNullOrWhiteSpace(value))
        {
            bindingContext.Result = ModelBindingResult.Success(null);
            return Task.CompletedTask;
        }

        // The value isn't null or whitespace,
        // and the type of the model is enumerable.
        // Get the enumerable's type, and a converter
        var elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0];
        var converter = TypeDescriptor.GetConverter(elementType);

        // Convert each item in the value list to the enumerable type
        var values = value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
            .Select(x => converter.ConvertFromString(x.Trim()))
            .ToArray();

        // Create an array of that type, and set it as the Model value
        var typedValues = Array.CreateInstance(elementType, values.Length);
        values.CopyTo(typedValues, 0);
        bindingContext.Model = typedValues;

        // return a successful result, passing in the Model
        bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
        return Task.CompletedTask;
    }
}

Затем используйте его в своем действии:

[HttpGet("({ids})", Name = "GetAuthorCollection")]
public IActionResult GetAuthorCollection(
    [ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable<int> ids)
{
    //enter code here
}

Узнал об этом из курса множественного числа: Создание RESTful API с помощью ASP.NET Core

Я очень рекомендую курсы Кевин Доккс!

fuzzy_logic 24.06.2020 01:32

Небольшой вариант ответа Пламена.

  • Кажется, что в массивах есть пустой GenericTypeArguments, поэтому добавлен GetElementType ()
  • Переименован класс, чтобы избежать конфликтов с классом инфраструктуры ArrayModelBinder.
  • Добавлена ​​проверка типа элемента по мере необходимости.
  • Дополнительные возможности для заключения массива в квадратные скобки.
public class CustomArrayModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (!bindingContext.ModelMetadata.IsEnumerableType)
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        var value = bindingContext.ValueProvider
            .GetValue(bindingContext.ModelName)
            .ToString();

        if (string.IsNullOrWhiteSpace(value))
        {
            bindingContext.Result = ModelBindingResult.Success(null);
            return Task.CompletedTask;
        }

        var elementType = bindingContext.ModelType.GetElementType() ??
            bindingContext.ModelType.GetTypeInfo().GenericTypeArguments.FirstOrDefault();

        if (elementType == null)
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        var converter = TypeDescriptor.GetConverter(elementType);

        var values = value.Split(',', StringSplitOptions.RemoveEmptyEntries)
            .Select(x => converter.ConvertFromString(Clean(x)))
            .ToArray();

        var typedValues = Array.CreateInstance(elementType, values.Length);
        values.CopyTo(typedValues, 0);
        bindingContext.Model = typedValues;

        bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
        return Task.CompletedTask;
    }

    private static string Clean(string str)
    {
        return str.Trim('(', ')').Trim('[', ']').Trim();
    }
}

Затем используйте с IEnumerable<T>, IList<T> или массивом T[]

[ModelBinder(BinderType = typeof(CustomArrayModelBinder))] IEnumerable<T> ids
                                                       ... T[] ids
                                                       ... IList<T> ids

Параметр может быть в пути или запросе с необязательными скобками.

[Route("resources/{ids}")]

resource/ids/1,2,3
resource/ids/(1,2,3)
resource/ids/[1,2,3]

[Route("resources")]

resource?ids=1,2,3
resource?ids=(1,2,3)
resource?ids=[1,2,3]

var elementType = bindingContext.ModelType.GetElementType (); в вашем CustomModelArrayBinder будет работать только с типами массивов. Таким образом, IEnumerable <T> и List <T> не будут работать. Скорее всего, это нормально, и мне это хорошо подходит. Я думаю, ваш ответ следует пересмотреть, чтобы убрать эти другие варианты.

iGanja 25.03.2021 20:54

@iGanja обновлен для поддержки IEnumerable <T>, IList <T>

yshehab 01.04.2021 21:48

Вместо [ab] с использованием строки запроса (рассмотрите 1000 идентификаторов), вы можете использовать [FromBody] и передать список идентификаторов в виде массива JSON:

public IActionResult ServicesByCategoryIds([FromBody] int[] ids)

Если речь идет о OpenAPI / Swagger, будет сгенерирована правильная спецификация:

    "parameters": [
      {
        "name": "ids",
        "in": "body",
        "required": true,
        "schema": {
          "type": "array",
          "items": {
            "type": "integer",
            "format": "int32"
          }
        }
      }
    ],

как видите, вам нужно изменить HTTP-глагол на HttpPost с правильным Content-Type, потому что теперь вы передаете параметры через Body. Вопрос связан с глаголом HttpGet

Zinov 28.08.2020 05:09

Другие вопросы по теме