在查询参数中接收锯齿状数组

Receive a jagged array in query parameters

我目前有一个控制器,它有一个获取一些信息的动作,这个动作接收一个锯齿状数组作为查询参数来过滤信息,例如:[["Day", ">=", "01.01.2021"],["User", "=", "SomeUserId"]].

我当前的行动宣言:

[HttpGet]
public async Task<object> Get(string[][] filters)
{
     ...
}

当我从客户端发出 AJAX 请求时,URL 按以下方式编码(DevTools 请求 header 参数视图):

filters[0][]: Day
filters[0][]: >=
filters[0][]: 01.07.2021
filters[1][]: User
filters[1][]: =
filters[1][]: SomeUserId

Url 编码仅供参考:...filters%5B0%5D%5B%5D=Day&filters%5B0%5D%5B%5D=%3E%3D&filters%5B0%5D%5B%5D=01.07.2021&filters%5B1%5D%5B%5D=User&filters%5B1%5D%5B%5D=%3D&filters%5B1%5D%5B%5D=SomeUserId

问题

收到上述信息时我的动作有两个空字符串数组的值string[2][]。下图是来自 VS 的过滤器变量的调试打印屏幕。

我应该连载吗?或者使用不同的结构?

一个选项是将输入包装在 class 中,例如

public class InputRequest
{
    public string Field { get; set; }
    public string Operator { get; set; }
    public string Value { get; set; }
}

然后使用自定义模型绑定器-

class InputRequestModelBinder : IModelBinder
{
    static readonly JsonSerializerOptions options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(List<InputRequest>)) return Task.CompletedTask;

        var modelName = bindingContext.ModelName;

        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var results = valueProviderResult.Select(t => JsonSerializer.Deserialize<InputRequest>(t, options)).ToList();

        bindingContext.Result = ModelBindingResult.Success(results);

        return Task.CompletedTask;

    }
}

最后,将模型绑定器挂接到控制器方法 -

[HttpGet]
[Route("show")]
public string Show([ModelBinder(typeof(InputRequestModelBinder))] List<InputRequest> req)
{
    //do something
}

用法示例 -

/SomeController/show?req=%7B%0A%20%20%22field%22%3A%20%22name%22%2C%0A%20%20%22operator%22%3A%20%22%3D%22%2C%0A%20%20%22value%22%3A%20%22tom%22%0A%7D&req=%7B%0A%20%20%22field%22%3A%20%22age%22%2C%0A%20%20%22operator%22%3A%20%22%3C%22%2C%0A%20%20%22value%22%3A%20%2220%22%0A%7D

解码后的 url 看起来像这样 -

/SomeController/show?req={
  "field": "name",
  "operator": "=",
  "value": "tom"
}&req={
  "field": "age",
  "operator": "<",
  "value": "20"
}

-

  • 您可以在 InputRequest
  • 中向您的 API 消费者明确说明合同中的期望值

Con -

  • 您的请求查询字符串长度增加,因此您可能很快就会达到限制。虽然你可以把它转换成一个POST方法,但是这样就违反了REST原则。

这是一个工作演示:

查看:

<button type="button" onclick="SendRequest()">Click</button>
@section Scripts
{
<script>
    function SendRequest() {
        var day = "Day";
        var simble = encodeURIComponent(">=");
        var date = "01.07.2021";
        var user = "UserName";
        var simble2 = "=";
        var id = "1";
        $.ajax({
            //url: "api/values?filters[0][0]=Day&filters[0][1]=>=&filters[0][2]=01.07.2021&filters[1][0]=User&filters[1][1]==&filters[1][2]=2"
            url: "api/values?filters[0][0]=" + day + "&filters[0][1]=" + simble + "&filters[0][2]=" + date + " &filters[1][0]=" + user + "&filters[1][1]=" + simble2 + "&filters[1][2]=" + id + "",
            type: 'GET',
            success: function (res) {
                alert("success");
            },
            error: function () {

            }
        })
    }
</script>
}

控制器:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    public void Get([FromQuery] string[][] filters)
    {

    }
}