在查询参数中接收锯齿状数组
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)
{
}
}
我目前有一个控制器,它有一个获取一些信息的动作,这个动作接收一个锯齿状数组作为查询参数来过滤信息,例如:[["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)
{
}
}