Я пытаюсь отправить массив целых чисел в свой метод действия, код выглядит так:
[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 с одним действием.
[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, как было предложено в обсуждении, которое вы связали.
Очень помогает !! Спасибо
Рекомендуем использовать новые ответы от yshehab или Plamen Yovchev ниже
Вы можете реализовать настраиваемый связыватель модели и идентификаторы, которые будут частью 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
Я очень рекомендую курсы Кевин Доккс!
Небольшой вариант ответа Пламена.
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 обновлен для поддержки IEnumerable <T>, IList <T>
Вместо [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
Отвечает ли это на ваш вопрос? Передать массив целых чисел в веб-API ASP.NET?