将数组传递给ASP网络核心Web API操作方法HttpGet

zor*_*nov 6 .net-core asp.net-core asp.net-core-webapi

我试图将整数数组发送到我的操作方法,代码看起来像这样:

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

我这样调用该方法:https:// localhost:44343 / api / accounts / servicesbycategoryids?ids = 1&ids = 2

但是,即使我在查询字符串中传递ID时,调用此方法时总会得到一个空数组。我正在使用.net core 2.1。

我搜索过的所有内容都表明这实际上是完成的方式。。。我在这里缺少什么吗?

谢谢!

Tao*_*hou 6

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();
    }
Run Code Online (Sandbox Code Playgroud)


ken*_*yzx 5

我创建了一个新的 Web api 类,只有一个操作。

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

然后使用与您相同的网址:

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

这是工作。


ysh*_*hab 5

Plamen 的回答略有不同。

  • 数组似乎有一个空的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后与IEnumerable<T>,IList<T>或数组一起使用T[]

[ModelBinder(BinderType = typeof(CustomArrayModelBinder))] IEnumerable<T> ids
                                                       ... T[] ids
                                                       ... IList<T> ids
Run Code Online (Sandbox Code Playgroud)

参数可以在带有可选括号的路径或查询中。

[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]
Run Code Online (Sandbox Code Playgroud)