Я использую страницы Razor для своего проекта на ядре dotnet 2.1, и приложение, похоже, не связывает мои свойства правильно, простые типы (типы 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)
в моем обработчике страницы вместо свойства columns в DataTableOptions, чтобы я мог вручную привязать свойства к моему классу: я получил полный список моих столбцов с привязанными к нему свойствами, за исключением свойства DataTableColumnSearch DataTableColumn, которое также является сложным типом это оказалось нулевым.
public async Task<IActionResult> OnGetDTResponseAsync(List<Dictionary<string, object>> columns)
тоже не работает.
Вот как выглядит запрос в скрипте:
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% 5D2 = false 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% 5Bsearch 5D% 5Bname% 5D = & columns% 5B4% 5D% 5Bsearchable% 5D = true & column s% 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
Мне пришлось создать собственный класс привязки модели для обработки этого сценария. По какой-то причине список коллекций сложного объекта, который имеет другой сложный объект как часть его свойств, не может быть автоматически правильно привязан к страницам ядра 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))]