无法绑定字符串索引查询字符串参数

failing to bind string indexed query string parameters

我正在尝试绑定一些由字符串键索引的查询字符串参数,但我似乎无法让它工作

这是我试图绑定的值

search[value]: Exception happ...
search[regex]: false

这是我要绑定的模型 getLogsAjax(DataTableAjaxPostModel model)

public class DataTableAjaxPostModel
{
    public int draw { get; set; }
    public int start { get; set; }
    public int length { get; set; }
    public List<Column> columns { get; set; }
    public search search { get; set; }
    public List<Order> order { get; set; }
}

public class search
{
    public string value { get; set; }
    public string regex { get; set; }
}

除搜索 class 对象外,模型的其余部分已正确绑定,我三次检查请求是否包含该对象的值,我在这里缺少什么? p.s。据说相同的代码在 .net 核心之前工作

代码的更多背景知识会有所帮助,例如实际执行绑定的代码部分,但这里是一个带有查询参数绑定的 dotnetcore 控制器示例。 C# 中的常见做法是 class 名称和字段均为大写 FYI。

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
public class SampleController : Controller
{
    [HttpGet]
    [Route("")]
    public IActionResult ExampleGet([FromQuery] DataTableAjaxPostModel dataTableAjaxPostModel)
    {
        // You should be able to debug and see the value here
        var result = dataTableAjaxPostModel.search;
        return Ok();
    }

    public class DataTableAjaxPostModel
    {
        public int draw { get; set; }
        public int start { get; set; }
        public int length { get; set; }
        public List<Column> columns { get; set; }
        public search search { get; set; }
        public List<Order> order { get; set; }
    }

    public class search
    {
        public string value { get; set; }
        public string regex { get; set; }
    }
}

似乎没有人对此有答案,所以我采取了不同的路线并编写了我自己的自定义活页夹,如果有更好的答案出现,我会接受它而不是这个,以后可能会重构它(哈哈哈 IKR !)

public class DTModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        try
        {
            var result = new DataTableAjaxPostModel();
            if (bindingContext.HttpContext.Request.Query.Keys.Contains("draw"))
                result.draw = int.Parse(bindingContext.ValueProvider.GetValue("draw").FirstValue);
            if (bindingContext.HttpContext.Request.Query.Keys.Contains("search[value]") &&
                bindingContext.HttpContext.Request.Query.Keys.Contains("search[regex]"))
                result.search = new search()
                {
                    regex = bindingContext.ValueProvider.GetValue("search[regex]").FirstValue,
                    value = bindingContext.ValueProvider.GetValue("search[value]").FirstValue
                };
            //...
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        catch
        {
            bindingContext.Result = ModelBindingResult.Failed();
        }

        return Task.CompletedTask;
    }
}
  1. 您不需要手动绑定每个字段。使用反射会很容易。
  2. 此外,无需手动绑定那些外部模型的属性(DataTableAjaxPostModel 的属性)。那是因为它们将由 内置 模型绑定器完成。

实施

创建自定义活页夹 QueryStringDictSyntaxBinder<TModel>:

internal class QueryStringDictSyntaxBinder<TModel> : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));
        try
        {
            var result = Activator.CreateInstance<TModel>();
            foreach(var pi in typeof(TModel).GetProperties())
            {
                var modelName = bindingContext.ModelName;
                var qsFieldName = $"{modelName}[{pi.Name}]";
                var field= bindingContext.HttpContext.Request.Query[qsFieldName].FirstOrDefault();
                if(field != null){
                    pi.SetValue(result,field);
                }
                // do nothing if null , or add model binding failure messages if you like
            }
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        catch
        {
            bindingContext.Result = ModelBindingResult.Failed();
        }

        return Task.CompletedTask;
    }
}

然后用 [ModelBinder(typeof(QueryStringDictSyntaxBinder<search>))] 装饰 search 属性 :

public class DataTableAjaxPostModel
{
    public int draw { get; set; }
    public int start { get; set; }
    public int length { get; set; }
    public List columns { get; set; }

    [ModelBinder(typeof(QueryStringDictSyntaxBinder<search>))]
    public search search { get; set; }

    public List order { get; set; }
}

测试用例:

我用以下请求对其进行了测试,它对我来说工作正常:

?draw=1&search[value]=abc&search[regex]=(.*)&
?draw=1&sEarCh[value]=opq&Search[regex]=([^123]*)&
?draw=1&seaRch[value]=rst&Search[regex]=(.*)&
?draw=1&Search[value]=abc&
?draw=1&