我正在尝试将整数数组发送给我的操作方法,代码看起来像这样:
[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
但是当我调用此方法时,即使在查询字符串中传递ID时,始终会得到一个空数组。我正在使用.net core 2.1。
我搜索过的所有内容都表明这实际上是完成操作的方式。 。 。 这里有我想念的东西吗?
谢谢!
答案 0 :(得分:5)
Array
参数的绑定失败是Asp.Net Core 2.1
下的一个已知问题,已记录Array or List in query string does not get parsed #7712。
要暂时解决此问题,您可以像下面这样设置FromQuery Name Property
:
[HttpGet()]
[Route("ServicesByCategoryIds")]
public async Task<IActionResult> ServicesByCategoryIds([FromQuery(Name = "ids")]int[] ids)
{
return Ok();
}
答案 1 :(得分:1)
我创建一个新的Web api类,只需执行一次操作即可。
[Produces("application/json")]
[Route("api/accounts")]
public class AccountsController : Controller
{
[HttpGet]
[Route("servicesbycategoryids")]
public IActionResult ServicesByCategoryIds([FromQuery] int[] ids)
{
return Ok();
}
}
然后使用与您相同的网址:
http://localhost:2443/api/accounts/servicesbycategoryids?ids=1&ids=2
正在工作。
答案 2 :(得分:0)
您可以将自定义模型绑定程序和ID实施为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<Guid> ids)
{
//enter code here
}
从多元视角课程中学到了这一点:使用ASP.NET Core构建RESTful API
答案 3 :(得分:0)
普拉门的答案略有不同。
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();
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
[ModelBinder(BinderType = typeof(CustomArrayModelBinder))] IEnumerable<T> ids
... T[] ids
... List<T> ids
该参数可以在路径中或带有可选括号的查询中。
[Route("resource/{ids}")]
resource/ids/1,2,3
resource/ids/(1,2,3)
resource/ids/[1,2,3]
[Route("resource")]
resource?ids=1,2,3
resource?ids=(1,2,3)
resource?ids=[1,2,3]
答案 4 :(得分:-1)
您可以使用SELECT id, l1.campaign, event_type,
COALESCE(date_offered, date_ordered, date_delivered) AS event_date,
COALESCE(l1.quantity,l2.quantity) AS quantity
FROM logistics l1
JOIN ( SELECT campaign, MAX(quantity) AS quantity
FROM logistics
WHERE event_type = 'ordered'
GROUP BY campaign ) l2
ON l2.campaign = l1.campaign
而不是[ab]使用查询字符串(考虑1000个ID),并将ID列表作为JSON数组传递:
[FromBody]
只要涉及OpenAPI / Swagger,就会生成正确的规范:
public IActionResult ServicesByCategoryIds([FromBody] int[] ids)