ASP.NET Core 3.1 中的数据表服务器端处理

Datatables server-side processing in ASP.NET Core 3.1

提问人:Russell Chidhakwa 提问时间:10/10/2020 最后编辑:Russell Chidhakwa 更新时间:12/10/2020 访问量:12501

问:

我是使用 AJAX 调用的 Datatables 的新手。我需要对数千条记录实现服务器端处理。我正在遵循一个教程,但我在某个地方对服务器端处理感到困惑。

我在尝试从数据源呈现数据时遇到错误。让我发布所有相关代码,并希望您能帮助我确定我哪里出错了。由于我是 Datatables 和 Ajax 的新手,我将不胜感激更多带有示例的答案、文本答案以及代码或指向演示 ASP.NET CORE 3.1 中服务器端处理的教程的链接。

感谢您的时间和帮助。

铌。我从教程中获取了实现和配置,并尝试对其进行自定义。

下面是 HTML 表格及其模型:

@model IEnumerable<StudentApplications>
<table id="custom-datatable" class="mb-5 display table table-bordered" style="width:100%">
                <thead>
                    <tr>
                        <th>
                            @Html.DisplayNameFor(model => model.ApplicationId)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.Firstname)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.Surname)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.ApplicationFor)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.SubmissionDate)
                        </th>
                        <th></th>
                    </tr>
                </thead>
                <tfoot>
                    <tr>
                        <th>
                            @Html.DisplayNameFor(model => model.ApplicationId)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.Firstname)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.Surname)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.ApplicationFor)
                        </th>
                        <th>
                            @Html.DisplayNameFor(model => model.SubmissionDate)
                        </th>
                        <th></th>
                    </tr>
                </tfoot>
            </table>

下面是将 HTML 表初始化为 datatable 的 javascript 文件和一些配置:

$(document).ready(function () {
    $('#custom-datatable').DataTable({

        // Design Assets
        stateSave: true,
        autoWidth: true,
        // ServerSide Setups
        processing: true,
        serverSide: true,
        // Paging Setups
        paging: true,
        // Searching Setups
        searching: { regex: true },
        // Ajax Filter
        ajax: {
            url: "/myapplications/data",
            type: "POST",
            contentType: "application/json",
            dataType: "json",
            data: function (d) {
                return JSON.stringify(d);
            }
        },
        // Columns Setups
        columns: [
            { data: "ApplicationId" },
            { data: "Firstname" },
            { data: "Surname" },
            { data: "ApplicationFor" },
            { data: "SubmissionDate" }

            //// For Student.Id
            //{ "data": "applicationId", "name": "ApplicationId" },
            //// For Student.Firstname
            //{ "data": "firstname", "name": "Firstname" },
            //// For Student.Surname
            //{ "data": "surname", "name": "Surname" },
            //// For Student.ApplicationFor
            //{ "data": "applicationFor", "name": "ApplicationFor" },
            //// For Student.SubmissionDate
            //{ "data": "submissionDate", "name": "SubmissionDate" }
        ],
        // Column Definitions
        columnDefs: [
            { targets: "no-sort", orderable: false },
            { targets: "no-search", searchable: false },
            {
                targets: "trim",
                render: function (data, type, full, meta) {
                    if (type === "display") {
                        data = strtrunc(data, 10);
                    }

                    return data;
                }
            },
            { targets: "date-type", type: "date-eu" },
            {
                targets: 10,
                data: null,
                orderable: false
            },
        ]
    });

});

下面是获取数据的方法:

// loading datatable
        [HttpPost]
        [Route("myapplications/data")]
        public async Task<IActionResult> Data([FromBody] DtParameters dtParameters)
        { 
            searchBy = dtParameters.Search?.Value;

            // if we have an empty search then just order the results by Id ascending
            var orderCriteria = "ApplicationId";
            var orderAscendingDirection = true;

            if (dtParameters.Order != null)
            {
                // in this example we just default sort on the 1st column
                orderCriteria = dtParameters.Columns[dtParameters.Order[0].Column].Data;
                orderAscendingDirection = dtParameters.Order[0].Dir.ToString().ToLower() == "asc";
            }

            var result = context.AspNetStudentApplications.AsQueryable();

            if (!string.IsNullOrEmpty(searchBy))
            {
                result = result.Where(r => r.ApplicationId != null && r.ApplicationId.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.Firstname != null && r.Firstname.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.Surname != null && r.Surname.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.ApplicationFor != null && r.ApplicationFor.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.SubmissionDate != null && r.SubmissionDate.ToUpper().Contains(searchBy.ToUpper()));
            }

            result = orderAscendingDirection ? result.OrderByDynamic(orderCriteria, DtOrderDir.Asc) : result.OrderByDynamic(orderCriteria, DtOrderDir.Desc);

            // now just get the count of items (without the skip and take) - eg how many could be returned with filtering
            var filteredResultsCount = await result.CountAsync();
            var totalResultsCount = await context.AspNetStudentApplications.CountAsync();

            return Json(new DtResult<StudentApplications>
            {
                Draw = dtParameters.Draw,
                RecordsTotal = totalResultsCount,
                RecordsFiltered = filteredResultsCount,
                Data = await result
                    .Skip(dtParameters.Start)
                    .Take(dtParameters.Length)
                    .ToListAsync()
            });
        }

下面是 DtParameters 类和其他与 Datatables 相关的类:

/// <summary>
/// A full result, as understood by jQuery DataTables.
/// </summary>
/// <typeparam name="T">The data type of each row.</typeparam>
public class DtResult<T>
{
    /// <summary>
    /// The draw counter that this object is a response to - from the draw parameter sent as part of the data request.
    /// Note that it is strongly recommended for security reasons that you cast this parameter to an integer, rather than simply echoing back to the client what it sent in the draw parameter, in order to prevent Cross Site Scripting (XSS) attacks.
    /// </summary>
    [JsonProperty("draw")]
    public int Draw { get; set; }

    /// <summary>
    /// Total records, before filtering (i.e. the total number of records in the database)
    /// </summary>
    [JsonProperty("recordsTotal")]
    public int RecordsTotal { get; set; }

    /// <summary>
    /// Total records, after filtering (i.e. the total number of records after filtering has been applied - not just the number of records being returned for this page of data).
    /// </summary>
    [JsonProperty("recordsFiltered")]
    public int RecordsFiltered { get; set; }

    /// <summary>
    /// The data to be displayed in the table.
    /// This is an array of data source objects, one for each row, which will be used by DataTables.
    /// Note that this parameter's name can be changed using the ajax option's dataSrc property.
    /// </summary>
    [JsonProperty("data")]
    public IEnumerable<T> Data { get; set; }

    /// <summary>
    /// Optional: If an error occurs during the running of the server-side processing script, you can inform the user of this error by passing back the error message to be displayed using this parameter.
    /// Do not include if there is no error.
    /// </summary>
    [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)]
    public string Error { get; set; }

    public string PartialView { get; set; }
}

/// <summary>
/// The additional columns that you can send to jQuery DataTables for automatic processing.
/// </summary>
public abstract class DtRow
{
    /// <summary>
    /// Set the ID property of the dt-tag tr node to this value
    /// </summary>
    [JsonProperty("DT_RowId")]
    public virtual string DtRowId => null;

    /// <summary>
    /// Add this class to the dt-tag tr node
    /// </summary>
    [JsonProperty("DT_RowClass")]
    public virtual string DtRowClass => null;

    /// <summary>
    /// Add the data contained in the object to the row using the jQuery data() method to set the data, which can also then be used for later retrieval (for example on a click event).
    /// </summary>
    [JsonProperty("DT_RowData")]
    public virtual object DtRowData => null;

    /// <summary>
    /// Add the data contained in the object to the row dt-tag tr node as attributes.
    /// The object keys are used as the attribute keys and the values as the corresponding attribute values.
    /// This is performed using using the jQuery param() method.
    /// Please note that this option requires DataTables 1.10.5 or newer.
    /// </summary>
    [JsonProperty("DT_RowAttr")]
    public virtual object DtRowAttr => null;
}

/// <summary>
/// The parameters sent by jQuery DataTables in AJAX queries.
/// </summary>
public class DtParameters
{
    /// <summary>
    /// Draw counter.
    /// This is used by DataTables to ensure that the Ajax returns from server-side processing requests are drawn in sequence by DataTables (Ajax requests are asynchronous and thus can return out of sequence).
    /// This is used as part of the draw return parameter (see below).
    /// </summary>
    public int Draw { get; set; }

    /// <summary>
    /// An array defining all columns in the table.
    /// </summary>
    public DtColumn[] Columns { get; set; }

    /// <summary>
    /// An array defining how many columns are being ordering upon - i.e. if the array length is 1, then a single column sort is being performed, otherwise a multi-column sort is being performed.
    /// </summary>
    public DtOrder[] Order { get; set; }

    /// <summary>
    /// Paging first record indicator.
    /// This is the start point in the current data set (0 index based - i.e. 0 is the first record).
    /// </summary>
    public int Start { get; set; }

    /// <summary>
    /// Number of records that the table can display in the current draw.
    /// It is expected that the number of records returned will be equal to this number, unless the server has fewer records to return.
    /// Note that this can be -1 to indicate that all records should be returned (although that negates any benefits of server-side processing!)
    /// </summary>
    public int Length { get; set; }

    /// <summary>
    /// Global search value. To be applied to all columns which have searchable as true.
    /// </summary>
    public DtSearch Search { get; set; }

    /// <summary>
    /// Custom column that is used to further sort on the first Order column.
    /// </summary>
    public string SortOrder => Columns != null && Order != null && Order.Length > 0
        ? (Columns[Order[0].Column].Data +
           (Order[0].Dir == DtOrderDir.Desc ? " " + Order[0].Dir : string.Empty))
        : null;

    /// <summary>
    /// For Posting Additional Parameters to Server
    /// </summary>
    public IEnumerable<string> AdditionalValues { get; set; }

}

/// <summary>
/// A jQuery DataTables column.
/// </summary>
public class DtColumn
{
    /// <summary>
    /// Column's data source, as defined by columns.data.
    /// </summary>
    public string Data { get; set; }

    /// <summary>
    /// Column's name, as defined by columns.name.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Flag to indicate if this column is searchable (true) or not (false). This is controlled by columns.searchable.
    /// </summary>
    public bool Searchable { get; set; }

    /// <summary>
    /// Flag to indicate if this column is orderable (true) or not (false). This is controlled by columns.orderable.
    /// </summary>
    public bool Orderable { get; set; }

    /// <summary>
    /// Search value to apply to this specific column.
    /// </summary>
    public DtSearch Search { get; set; }
}

/// <summary>
/// An order, as sent by jQuery DataTables when doing AJAX queries.
/// </summary>
public class DtOrder
{
    /// <summary>
    /// Column to which ordering should be applied.
    /// This is an index reference to the columns array of information that is also submitted to the server.
    /// </summary>
    public int Column { get; set; }

    /// <summary>
    /// Ordering direction for this column.
    /// It will be dt-string asc or dt-string desc to indicate ascending ordering or descending ordering, respectively.
    /// </summary>
    public DtOrderDir Dir { get; set; }
}

/// <summary>
/// Sort orders of jQuery DataTables.
/// </summary>
public enum DtOrderDir
{
    Asc,
    Desc
}

/// <summary>
/// A search, as sent by jQuery DataTables when doing AJAX queries.
/// </summary>
public class DtSearch
{
    /// <summary>
    /// Global search value. To be applied to all columns which have searchable as true.
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// true if the global filter should be treated as a regular expression for advanced searching, false otherwise.
    /// Note that normally server-side processing scripts will not perform regular expression searching for performance reasons on large data sets, but it is technically possible and at the discretion of your script.
    /// </summary>
    public bool Regex { get; set; }
}

这是我的空表: Basic Datatable features have been applied

以下是我在尝试加载数据时遇到的错误: This is the error I am getting when trying to load data

我哪里弄错了?

以下是发生异常的位置: enter image description here

@HMZ实现,我看到空记录(下图):

我看到此警报The Alert

卡在处理上 Stuck on processing

当行数发生变化时,我看到这个空表: Empty table

jQuery ajax ASP.Net-Core DataTable 服务器端

评论

0赞 HMZ 10/10/2020
请显示控制台错误而不是警报,并确保在服务器端包含任何异常。
0赞 Russell Chidhakwa 10/10/2020
@HMZ:我已经更新了问题,并在首次出现异常的地方发布了
0赞 HMZ 10/10/2020
为此,您需要一个自定义模型活页夹。我将发布一个工作示例。
0赞 Russell Chidhakwa 10/10/2020
@HMZ:我很期待。我真的很感谢你抽出时间
0赞 Abrar Jahin 12/10/2020
嗨,@RussellChidhakwa,您能否提供教程的链接

答:

5赞 HMZ 10/10/2020 #1

这是 Datatables 服务器端处理的一个工作示例。这是一个示例,可能需要修改才能在您的应用程序中工作。

法典

数据表参数:

[ModelBinder(BinderType = typeof(DataTableModelBinder))]
public class DataTablesResult
{
    public int Draw { get; set; }
    public int Start { get; set; }
    public int Length { get; set; }
    public Search Search { get; set; }
    public List<ColumnOrder> Order { get; set; }
    public List<Column> Columns { get; set; }
}

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

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

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

一个自定义模型绑定器,用于在服务器端正确绑定表参数:DataTablesResult

public class DataTableModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var request = bindingContext.HttpContext.Request;

        // Retrieve request data
        var draw = Convert.ToInt32(request.Query["draw"]);
        var start = Convert.ToInt32(request.Query["start"]);
        var length = Convert.ToInt32(request.Query["length"]);

        // Search
        var search = new Search
        {
            Value = request.Query["search[value]"],
            Regex = Convert.ToBoolean(request.Query["search[regex]"])
        };

        // Order
        var o = 0;
        var order = new List<ColumnOrder>();
        while (!StringValues.IsNullOrEmpty(request.Query["order[" + o + "][column]"]))
        {
            order.Add(new ColumnOrder
            {
                Column = Convert.ToInt32(request.Query["order[" + o + "][column]"]),
                Dir = request.Query["order[" + o + "][dir]"]
            });
            o++;
        }

        // Columns
        var c = 0;
        var columns = new List<Column>();
        while (!StringValues.IsNullOrEmpty(request.Query["columns[" + c + "][name]"]))
        {
            columns.Add(new Column
            {
                Data = request.Query["columns[" + c + "][data]"],
                Name = request.Query["columns[" + c + "][name]"],
                Orderable = Convert.ToBoolean(request.Query["columns[" + c + "][orderable]"]),
                Searchable = Convert.ToBoolean(request.Query["columns[" + c + "][searchable]"]),
                Search = new Search
                {
                    Value = request.Query["columns[" + c + "][search][value]"],
                    Regex = Convert.ToBoolean(request.Query["columns[" + c + "][search][regex]"])
                }
            });
            c++;
        }

        var result = new DataTablesResult
        {
            Draw = draw,
            Start = start,
            Length = length,
            Search = search,
            Order = order,
            Columns = columns
        };

        bindingContext.Result = ModelBindingResult.Success(result);
        return Task.CompletedTask;
    }
}

服务器端操作:

[HttpGet]
public async Task<IActionResult> DataAjax(DataTablesResult tableParams)
{
    var query = dataWrapper.YourDataSet.GetAll();

    var totalCount = await query.CountAsync();

    if (tableParams.Search != null)
        query = query.Where(c => c.Firstname.Contains(tableParams.Search.Value)
        || c.Surname.Contains(tableParams.Search.Value));
       //Other search queries goes here

    if (tableParams.Order.Count > 0)
    {
        if (tableParams.Order[0].Dir == "asc")
            query = query.OrderBy(c => EF.Property<string>(c, tableParams.Columns[tableParams.Order[0].Column].Name));
        else
            query = query.OrderByDescending(c => EF.Property<string>(c, tableParams.Columns[tableParams.Order[0].Column].Name));
    }
    //In this example multi order is disabled so we can order by any column dynamically

    var result = await query.AsNoTracking().Select(E => new { Count = query.Count(), E = E }).Skip(tableParams.Start).Take(tableParams.Length).ToListAsync();
    var pureData = result.Select(E => E.E);

    if (result.Count == 0)
        return Ok(new { tableParams.Draw, recordsTotal = 0, recordsFiltered = 0, data = Enumerable.Empty<string>() });

    return Ok(new { tableParams.Draw, recordsTotal = totalCount, recordsFiltered = result.Select(c => c.Count).FirstOrDefault(), data = pureData });
}

数据表配置:

var table = $("#dataTable").DataTable({
    serverSide: true,
    processing: true,
    ajax: {
        url: "/Controller/DataAjax",
        method: "GET",
        dataType: "json"
    },
    select: true,
    orderMulti: false, //Multi column order is disabled
    columnDefs: [{
        targets: [], //Here you can specify targets for cell ellipsis
        render: $.fn.dataTable.render.ellipsis(10, true)
    },
    {
        targets: [], //Disable search on targeted columns
        searchable: false
    },
    {
        targets: [], //Disable order on targeted columns
        orderable: false
    }],
    columns: [
        { "name": "ApplicationId" } //Here your column names should match your db columns in order to have dynamic order.
    ]
});

评论

0赞 Russell Chidhakwa 10/10/2020
我很感激。让我看看
0赞 Russell Chidhakwa 10/10/2020
我正在实现你的代码。我可能需要这里的帮助:'var query = dataWrapper.YourDataSet.GetAll();'在这种情况下,dataWrapper 是什么?
0赞 HMZ 10/10/2020
@RussellChidhakwa 在您的情况下,这将是: .DBContextcontext.AspNetStudentApplications.AsQueryable()
0赞 Russell Chidhakwa 10/10/2020
我很感激。让我继续实施
0赞 Russell Chidhakwa 10/10/2020
我已经实施了您的解决方案,但我现在面临另一个问题。我不再在输出中看到任何异常。在初始重新加载时,我卡在“正在处理”上,当我更改要显示的行数时,我看到一个带有空行的警报。我可以看到数据正在被拉取,但没有显示。让我发布图片。我发布了一些图片。在输出中,我看不到任何错误
4赞 Rena 10/13/2020 #2

代码中需要改进的内容:

  1. 核心 asp.net DataTable 默认以小写首字母渲染 json 数据,因此需要如下所示进行更改:

    列:[ { data: “applicationId” }, { data: “名字” }, { data: “姓氏” }, { data: “applicationFor” }, { data: “submissionDate” } ]

  2. 默认的 DataTable 包含分页、排序和搜索。

  3. 当我测试您的代码时,它会在前端收到以下错误消息(您可以在浏览器中按以检查错误消息)。不确定是否会收到此错误,因为 DataTable 的版本可能不同:F12

    TypeError:无法将属性“nTf”设置为 undefined

我搜索了错误并得出结论,它是由表页脚中的元素数与表头中的元素数不同引起的。但是我在您的代码中找到了 和 的数字是相同的。thththeadtfoot

与传统 DataTable 略有不同的是,在 和 的两端都有空。所以我试了一下,然后当我删除 in 但保持 in 时它会起作用:ththeadtfootthtfootththead

<thead>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.ApplicationId)
        </th>
        ...
        <th></th>
    </tr>
</thead>
<tfoot>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.ApplicationId)
        </th>
        ....
        @*<th></th>*@  //remove this...
    </tr>
</tfoot>

下面是一个工作演示:

型:

public class StudentApplications
{
    public int ApplicationId { get; set; }
    public string Firstname { get; set; }
    public string Surname { get; set; }
    public string ApplicationFor { get; set; }
    public string SubmissionDate { get; set; }
}

视图:

@model IEnumerable<StudentApplications>
<table id="custom-datatable" class="mb-5 display table table-bordered" style="width:100%">
     <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.ApplicationId)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Firstname)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Surname)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ApplicationFor)
            </th>
            <th>
                Date
            </th>
            <th></th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.ApplicationId)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Firstname)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Surname)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ApplicationFor)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.SubmissionDate)
            </th>
            @*<th></th>*@
        </tr>
    </tfoot>
</table>
@section Scripts
{
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.css">
    <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.js"></script>
    <script>
        $(document).ready(function () {
            $('#custom-datatable').DataTable({
                ajax: {
                    url: "/Home/data",
                    type:"POST"
                },
                columns: [
                    { data: "applicationId" },
                    { data: "firstname" },
                    { data: "surname" },
                    { data: "applicationFor" },
                    { data: "submissionDate" }
                ]

            });

        });
    </script>
}

控制器:

[HttpPost]
public ActionResult Data()
{
    var model = new List<StudentApplications>()
    {
        new StudentApplications(){ ApplicationId=1, ApplicationFor="aa", Firstname="Rena", SubmissionDate="2020-8-9", Surname="Ni"},
        new StudentApplications(){ ApplicationId=2, ApplicationFor="bb", Firstname="Sherry", SubmissionDate="2020-10-7", Surname="Chen"},
        new StudentApplications(){ ApplicationId=3, ApplicationFor="cc", Firstname="Xing", SubmissionDate="2020-5-10", Surname="Zou"},
        new StudentApplications(){ ApplicationId=4, ApplicationFor="dd", Firstname="a", SubmissionDate="2020-5-10", Surname="Zou"},
        new StudentApplications(){ ApplicationId=5, ApplicationFor="ee", Firstname="b", SubmissionDate="2020-5-10", Surname="sd"},
        new StudentApplications(){ ApplicationId=6, ApplicationFor="ff", Firstname="c", SubmissionDate="2020-5-10", Surname="df"},
        new StudentApplications(){ ApplicationId=7, ApplicationFor="gg", Firstname="d", SubmissionDate="2020-5-10", Surname="Zdfgou"},
        new StudentApplications(){ ApplicationId=8, ApplicationFor="hh", Firstname="e", SubmissionDate="2020-5-10", Surname="dfg"},
        new StudentApplications(){ ApplicationId=9, ApplicationFor="ii", Firstname="f", SubmissionDate="2020-5-10", Surname="dfg"},
        new StudentApplications(){ ApplicationId=10, ApplicationFor="jj", Firstname="g", SubmissionDate="2020-5-10", Surname="vbc"},
        new StudentApplications(){ ApplicationId=11, ApplicationFor="kk", Firstname="h", SubmissionDate="2020-5-10", Surname="hj"},
        new StudentApplications(){ ApplicationId=12, ApplicationFor="ll", Firstname="i", SubmissionDate="2020-5-10", Surname="hjk"},
        new StudentApplications(){ ApplicationId=13, ApplicationFor="mm", Firstname="j", SubmissionDate="2020-5-10", Surname="tyu"},
    };
    return Json(new {Data = model});
}

Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();                
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

结果:

enter image description here

评论

0赞 Russell Chidhakwa 10/13/2020
让我试试你的建议和实施。我真的很感谢你的时间。
0赞 Rena 10/14/2020
嗨,@RussellChidhakwa,愿你成功!等待您的回复。
0赞 Russell Chidhakwa 10/14/2020
您好@Rena,很抱歉回复晚了。现在我正在从头开始尝试您的解决方案。我把代码搞砸了。我今天会更新你。
0赞 Russell Chidhakwa 10/14/2020
我创建了一个新的测试项目,将命名约定更改为 camelCasing 并删除了空列。现在我被困在处理上。我将获取数据的方法作为 Json 放在 try catch 块中,没有例外。数据仍未显示。因为我做了一个新项目,为了避免混淆,我会把它作为一个新问题问,然后邀请你看代码。
0赞 Russell Chidhakwa 10/15/2020
你好@Rena!我在这里转发了这个问题并提供了所有代码。请看一看:stackoverflow.com/questions/64359301/...
4赞 Russell Chidhakwa 10/16/2020 #3

我发现了问题。我缺少 JsonSerializer,我将其添加到我的Startup.cs类中。

此方法工作正常:

[HttpPost]
        public async Task<IActionResult> LoadTable([FromBody] DtParameters dtParameters)
        {
            var searchBy = dtParameters.Search?.Value;

            // if we have an empty search then just order the results by Id ascending
            var orderCriteria = "Id";
            var orderAscendingDirection = true;

            if (dtParameters.Order != null)
            {
                // in this example we just default sort on the 1st column
                orderCriteria = dtParameters.Columns[dtParameters.Order[0].Column].Data;
                orderAscendingDirection = dtParameters.Order[0].Dir.ToString().ToLower() == "asc";
            }

            var result = context.TestRegisters.AsQueryable();

            if (!string.IsNullOrEmpty(searchBy))
            {
                result = result.Where(r => r.Name != null && r.Name.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.FirstSurname != null && r.FirstSurname.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.SecondSurname != null && r.SecondSurname.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.Street != null && r.Street.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.Phone != null && r.Phone.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.ZipCode != null && r.ZipCode.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.Country != null && r.Country.ToUpper().Contains(searchBy.ToUpper()) ||
                                           r.Notes != null && r.Notes.ToUpper().Contains(searchBy.ToUpper()));
            }

            result = orderAscendingDirection ? result.OrderByDynamic(orderCriteria, DtOrderDir.Asc) : result.OrderByDynamic(orderCriteria, DtOrderDir.Desc);

            // now just get the count of items (without the skip and take) - eg how many could be returned with filtering
            var filteredResultsCount = await result.CountAsync();
            var totalResultsCount = await context.TestRegisters.CountAsync();

            return Json(new DtResult<TestRegister>
            {
                Draw = dtParameters.Draw,
                RecordsTotal = totalResultsCount,
                RecordsFiltered = filteredResultsCount,
                Data = await result
                    .Skip(dtParameters.Start)
                    .Take(dtParameters.Length)
                    .ToListAsync()
            });
        }

这些 DtParameters 是正确的:

public class DtResult<T>
    {
        /// <summary>
        /// The draw counter that this object is a response to - from the draw parameter sent as part of the data request.
        /// Note that it is strongly recommended for security reasons that you cast this parameter to an integer, rather than simply echoing back to the client what it sent in the draw parameter, in order to prevent Cross Site Scripting (XSS) attacks.
        /// </summary>
        [JsonProperty("draw")]
        public int Draw { get; set; }

        /// <summary>
        /// Total records, before filtering (i.e. the total number of records in the database)
        /// </summary>
        [JsonProperty("recordsTotal")]
        public int RecordsTotal { get; set; }

        /// <summary>
        /// Total records, after filtering (i.e. the total number of records after filtering has been applied - not just the number of records being returned for this page of data).
        /// </summary>
        [JsonProperty("recordsFiltered")]
        public int RecordsFiltered { get; set; }

        /// <summary>
        /// The data to be displayed in the table.
        /// This is an array of data source objects, one for each row, which will be used by DataTables.
        /// Note that this parameter's name can be changed using the ajax option's dataSrc property.
        /// </summary>
        [JsonProperty("data")]
        public IEnumerable<T> Data { get; set; }

        /// <summary>
        /// Optional: If an error occurs during the running of the server-side processing script, you can inform the user of this error by passing back the error message to be displayed using this parameter.
        /// Do not include if there is no error.
        /// </summary>
        [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)]
        public string Error { get; set; }

        public string PartialView { get; set; }
    }

    /// <summary>
    /// The additional columns that you can send to jQuery DataTables for automatic processing.
    /// </summary>
    public abstract class DtRow
    {
        /// <summary>
        /// Set the ID property of the dt-tag tr node to this value
        /// </summary>
        [JsonProperty("DT_RowId")]
        public virtual string DtRowId => null;

        /// <summary>
        /// Add this class to the dt-tag tr node
        /// </summary>
        [JsonProperty("DT_RowClass")]
        public virtual string DtRowClass => null;

        /// <summary>
        /// Add the data contained in the object to the row using the jQuery data() method to set the data, which can also then be used for later retrieval (for example on a click event).
        /// </summary>
        [JsonProperty("DT_RowData")]
        public virtual object DtRowData => null;

        /// <summary>
        /// Add the data contained in the object to the row dt-tag tr node as attributes.
        /// The object keys are used as the attribute keys and the values as the corresponding attribute values.
        /// This is performed using using the jQuery param() method.
        /// Please note that this option requires DataTables 1.10.5 or newer.
        /// </summary>
        [JsonProperty("DT_RowAttr")]
        public virtual object DtRowAttr => null;
    }

    /// <summary>
    /// The parameters sent by jQuery DataTables in AJAX queries.
    /// </summary>
    public class DtParameters
    {
        //public DtParameters()
        //{
        //    Search = new DtSearch();
        //    Search.Value = "";
        //}

        /// <summary>
        /// Draw counter.
        /// This is used by DataTables to ensure that the Ajax returns from server-side processing requests are drawn in sequence by DataTables (Ajax requests are asynchronous and thus can return out of sequence).
        /// This is used as part of the draw return parameter (see below).
        /// </summary>
        public int Draw { get; set; }

        /// <summary>
        /// An array defining all columns in the table.
        /// </summary>
        public DtColumn[] Columns { get; set; }

        /// <summary>
        /// An array defining how many columns are being ordering upon - i.e. if the array length is 1, then a single column sort is being performed, otherwise a multi-column sort is being performed.
        /// </summary>
        public DtOrder[] Order { get; set; }

        /// <summary>
        /// Paging first record indicator.
        /// This is the start point in the current data set (0 index based - i.e. 0 is the first record).
        /// </summary>
        public int Start { get; set; }

        /// <summary>
        /// Number of records that the table can display in the current draw.
        /// It is expected that the number of records returned will be equal to this number, unless the server has fewer records to return.
        /// Note that this can be -1 to indicate that all records should be returned (although that negates any benefits of server-side processing!)
        /// </summary>
        public int Length { get; set; }

        /// <summary>
        /// Global search value. To be applied to all columns which have searchable as true.
        /// </summary>
        public DtSearch Search { get; set; }

        /// <summary>
        /// Custom column that is used to further sort on the first Order column.
        /// </summary>
        public string SortOrder => Columns != null && Order != null && Order.Length > 0
            ? (Columns[Order[0].Column].Data +
               (Order[0].Dir == DtOrderDir.Desc ? " " + Order[0].Dir : string.Empty))
            : null;

        /// <summary>
        /// For Posting Additional Parameters to Server
        /// </summary>
        public IEnumerable<string> AdditionalValues { get; set; }

    }

    /// <summary>
    /// A jQuery DataTables column.
    /// </summary>
    public class DtColumn
    {
        /// <summary>
        /// Column's data source, as defined by columns.data.
        /// </summary>
        public string Data { get; set; }

        /// <summary>
        /// Column's name, as defined by columns.name.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Flag to indicate if this column is searchable (true) or not (false). This is controlled by columns.searchable.
        /// </summary>
        public bool Searchable { get; set; }

        /// <summary>
        /// Flag to indicate if this column is orderable (true) or not (false). This is controlled by columns.orderable.
        /// </summary>
        public bool Orderable { get; set; }

        /// <summary>
        /// Search value to apply to this specific column.
        /// </summary>
        public DtSearch Search { get; set; }
    }

    /// <summary>
    /// An order, as sent by jQuery DataTables when doing AJAX queries.
    /// </summary>
    public class DtOrder
    {
        /// <summary>
        /// Column to which ordering should be applied.
        /// This is an index reference to the columns array of information that is also submitted to the server.
        /// </summary>
        public int Column { get; set; }

        /// <summary>
        /// Ordering direction for this column.
        /// It will be dt-string asc or dt-string desc to indicate ascending ordering or descending ordering, respectively.
        /// </summary>
        public DtOrderDir Dir { get; set; }
    }

    /// <summary>
    /// Sort orders of jQuery DataTables.
    /// </summary>
    public enum DtOrderDir
    {
        Asc,
        Desc
    }

    /// <summary>
    /// A search, as sent by jQuery DataTables when doing AJAX queries.
    /// </summary>
    public class DtSearch
    {
        /// <summary>
        /// Global search value. To be applied to all columns which have searchable as true.
        /// </summary>
        public string Value { get; set; }

        /// <summary>
        /// true if the global filter should be treated as a regular expression for advanced searching, false otherwise.
        /// Note that normally server-side processing scripts will not perform regular expression searching for performance reasons on large data sets, but it is technically possible and at the discretion of your script.
        /// </summary>
        public bool Regex { get; set; }
    }

此数据表配置正确:

$(document).ready(function () {
    $("#demoTable").DataTable({
        // Design Assets
        stateSave: true,
        autoWidth: true,
        // ServerSide Setups
        processing: true,
        serverSide: true,
        // Paging Setups
        paging: true,
        // Searching Setups
        searching: { regex: true },
        // Ajax Filter
        ajax: {
            url: "/TestRegisters/LoadTable",
            type: "POST",
            contentType: "application/json",
            dataType: "json",
            data: function (d) {
                return JSON.stringify(d);
            }
        },
        // Columns Setups
        columns: [
            { data: "id" },
            { data: "name" },
            { data: "firstSurname" },
            { data: "secondSurname" },
            { data: "street" },
            { data: "phone" },
            { data: "zipCode" },
            { data: "country" },
            { data: "notes" },
            { data: "creationDate" }
        ]
    });
});

这是我在创业时缺少的一行代码,以使其正常工作:

 services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

添加 JsonSerializer 后,我得到了这个结果: result

评论

0赞 Asad Naeem 2/26/2021
惊人的代码,它在第一时间就执行了。我只需要知道一件事。我添加了一个自定义类来分配一些值。但是该类在 DTParameters 中是不可访问的
1赞 Russell Chidhakwa 2/27/2021
@Asad Naeem:你可以发布你的代码,并解释你做了什么,你想实现什么,以及你遇到的问题。这样,开发人员将能够重新创建您的方案并提供实用的解决方案。