【问题标题】:Issue with Binding a List of complex type object - Dotnet Core 2.1 Razor Pages绑定复杂类型对象列表的问题 - Dotnet Core 2.1 Razor Pages
【发布时间】:2018-12-18 20:19:12
【问题描述】:

我在 dotnet core 2.1 上为我的项目使用 Razor 页面,并且应用程序似乎没有正确绑定我的属性,简单类型(int 和 string 类型)正确绑定但不是复杂类型列表,是有解决办法吗?

我的页面处理程序如下所示:

public async Task<IActionResult> OnGetDTResponseAsync(DataTableOptions options) {// Some Code}

当我使用调试器单步执行时,“DataTableOptions 选项”的所有简单类型属性都填充得很好,但复杂类型返回 null。

我的模型如下所示:

public class DataTableOptions
{
    public string Draw { get; set; }
    public int Start { get; set; }
    public int Length { get; set; }
    public List<DataTableColumnOrder> Order { get; set; }
    public List<DataTableColumn> Columns { get; set; }
    public DataTableColumnSearch Search { get; set; }
    public List<string> Params { get; set; }

    public DataTableOptions() { }

    public class DataTableColumn
    {
        public string Data { get; set; }
        public string Name { get; set; }
        public bool Searchable { get; set; }
        public bool Orderable { get; set; }
        public DataTableColumnSearch Search { get; set; }

        public DataTableColumn() { }
    }

    public class DataTableColumnSearch
    {
        public string Value { get; set; }
        public bool Regex { get; set; }

        public DataTableColumnSearch() { }
    }

    public class DataTableColumnOrder
    {
        public int Column { get; set; }
        public string Dir { get; set; }

        public DataTableColumnOrder() { }
    }
}

在尝试解决这个问题时,我尝试使用

public async Task<IActionResult> OnGetDTResponseAsync(List<Dictionary<string, string>> columns)

在我的页面处理程序中代替 DataTableOptions 的 columns 属性,这样我就可以手动将属性绑定到我的类:我得到了我的列的完整列表,它的属性绑定到它,除了 DataTableColumn 的 DataTableColumnSearch 属性也是一种复杂类型,结果为 null。

public async Task<IActionResult> OnGetDTResponseAsync(List<Dictionary<string, object>> columns) 

也不行。

这是请求在 fiddler 中的样子:

GET /CMS/Index?handler=DTResponse&draw=1&columns%5B0%5D%5Bdata%5D=id&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=false&columns%5B0%5D%5Borderable %5D=false&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=name&columns%5B1%5D%5Bname%5D =&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns %5B2%5D%5Bdata%5D=webPage.name&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D %5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=value&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=true&columns %5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=contentType.name&columns %5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=true&col umns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=&columns% 5B5%5D%5Bname%5D=&columns%5B5%5D%5Bsearchable%5D=false&columns%5B5%5D%5Borderable%5D=false&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch% 5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=2&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&_=1545122652329 HTTP/1.1

【问题讨论】:

    标签: c# .net datatables .net-core model-binding


    【解决方案1】:

    我必须构建一个自定义模型绑定类来处理这种情况。 由于某种原因,在核心 2.1 -Razor 页面中无法自动正确绑定具有另一个复杂对象作为其属性的一部分的复杂对象的集合列表。

    在下面查看我的解决方案:

    using Microsoft.AspNetCore.Mvc.ModelBinding;
    using RestaurantDataModel.Data.Requests;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace ExampleDataModel.Data
    {
    public class CustomDataTableEntityBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
    
            var allValues = bindingContext.HttpContext.Request.Query;
            DataTableOptions DTOs = new DataTableOptions {
                Draw = allValues.FirstOrDefault(a => a.Key == "draw").Value,
                Start = Convert.ToInt32(allValues.FirstOrDefault(a => a.Key == "start").Value),
                Length = Convert.ToInt32(allValues.FirstOrDefault(a => a.Key == "length").Value)
            };
    
            if (allValues.Any(a => a.Key.Length > 9 && a.Key.Substring(0, 9).Contains("columns")))
            {
                var myListIndex = 0;
                var myListIndexComparer = 0;
                var allColumns = allValues.Where(a => a.Key.Length > 9 && a.Key.Substring(0, 9).Contains("columns")).ToList();
                DataTableColumn DTC = new DataTableColumn();
                DataTableColumnSearch DTCS = new DataTableColumnSearch();
                DTOs.columns = new List<DataTableColumn>();
                foreach (var column in allColumns)
                {
                    var perColumnArray = column.Key.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
                    var rawIndex = perColumnArray[1];
    
                    if (!int.TryParse(rawIndex, out myListIndex))
                    {
                        return Task.CompletedTask;
                    }
    
                    if (myListIndexComparer != myListIndex)
                    {
                        DTC.search = DTCS;
                        DTOs.columns.Add(DTC);
                        DTC = new DataTableColumn();
                        DTCS = new DataTableColumnSearch();
                    }
                    myListIndexComparer = myListIndex;
                    switch (perColumnArray[2])
                    {
                        case "data":
                            DTC.data = column.Value;
                            break;
                        case "name":
                            DTC.name = column.Value;
                            break;
                        case "searchable":
                            DTC.searchable = String.IsNullOrWhiteSpace(column.Value) ? false : Convert.ToBoolean(column.Value);
                            break;
                        case "orderable":
                            DTC.orderable = String.IsNullOrWhiteSpace(column.Value) ? false : Convert.ToBoolean(column.Value);
                            break;
                        case "search":
                            if (perColumnArray[3] == "regex")
                            {
                                DTCS.regex = String.IsNullOrWhiteSpace(column.Value) ? false : Convert.ToBoolean(column.Value);
                            }
                            if (perColumnArray[3] == "value")
                            {
                                DTCS.value = column.Value;
                            }
                            break;
                    }
    
                    if(allColumns.IndexOf(column) == allColumns.IndexOf(allColumns.Last()))
                    {
                        DTC.search = DTCS;
                        DTOs.columns.Add(DTC);
                    }
                }
            }
            if (allValues.Any(a => a.Key.Length > 7 && a.Key.Substring(0, 7).Contains("order")))
            {
                var myListIndex = 0;
                var myListIndexComparer = 0;
                var allOrders = allValues.Where(a => a.Key.Length > 7 && a.Key.Substring(0, 7).Contains("order")).ToList();
                DataTableColumnOrder DTCO = new DataTableColumnOrder();
                DTOs.order = new List<DataTableColumnOrder>();
                foreach (var order in allOrders)
                {
                    var perColumnArray = order.Key.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
                    var rawIndex = perColumnArray[1];
    
                    if (!int.TryParse(rawIndex, out myListIndex))
                    {
                        return Task.CompletedTask;
                    }
    
                    if (myListIndexComparer != myListIndex)
                    {
                        DTOs.order.Add(DTCO);
                        DTCO = new DataTableColumnOrder();
                    }
                    myListIndexComparer = myListIndex;
                    switch (perColumnArray[2])
                    {
                        case "column":
                            DTCO.Column = Convert.ToInt32(order.Value);
                            break;
                        case "dir":
                            DTCO.Dir = order.Value;
                            break;
                    }
                    if(allOrders.IndexOf(order) == allOrders.IndexOf(allOrders.Last()))
                    {
                        DTOs.order.Add(DTCO);
                    }
                }
            }
            if (allValues.Any(a => a.Key.Length > 7 && a.Key.Substring(0, 8).Contains("search")))
            {
                var allSearches = allValues.Where(a => a.Key.Length > 8 && a.Key.Substring(0, 8).Contains("search")).ToList();
                DataTableColumnSearch DTCS = new DataTableColumnSearch();
                DTOs.search = new DataTableColumnSearch();
                foreach (var search in allSearches)
                {
                    var perColumnArray = search.Key.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
    
                    switch (perColumnArray[1])
                    {
                        case "value":
                            DTCS.value = search.Value;
                            break;
                        case "regex":
                            DTCS.regex = String.IsNullOrWhiteSpace(search.Value) ? false : Convert.ToBoolean(search.Value);
                            break;
                    }
                    if(allSearches.IndexOf(search) == allSearches.IndexOf(allSearches.Last()))
                    {
                        DTOs.search = DTCS;
                    }
                }
            }
    
            bindingContext.Result = ModelBindingResult.Success(DTOs);
            return Task.CompletedTask;
        }
    }
    
    }
    

    然后我将它添加到我的模型类的顶部:

    [ModelBinder(BinderType = typeof(CustomDataTableEntityBinder))]
    

    【讨论】:

      猜你喜欢
      • 2023-02-04
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 2019-07-05
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 2020-11-16
      相关资源
      最近更新 更多