65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET8 使用 DataTables.net – 第6部分 – 在 AJAX 中返回附加参数

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2024年7月24日

CPOL

3分钟阅读

viewsIcon

4549

downloadIcon

147

在 Asp.Net 8 MVC 应用程序中使用 jQuery DataTables.net 组件的实用指南。

1 ASP.NET8 使用 jQuery DataTables.net

我正在评估 jQuery DataTables.net 组件 [1] 在 ASP.NET8 项目中的使用,并创建了几个原型(概念验证)应用程序,这些应用程序将在这些文章中介绍。

 

1.1 本系列文章

本系列文章包括:

  • ASP.NET8 使用 DataTables.net – 第1部分 – 基础
  • ASP.NET8 使用 DataTables.net – 第2部分 – 操作按钮
  • ASP.NET8 使用 DataTables.net – 第3部分 – 状态保存
  • ASP.NET8 使用 DataTables.net – 第4部分 – 多语言
  • ASP.NET8 使用 DataTables.net – 第5部分 – 在 AJAX 中传递附加参数
  • ASP.NET8 使用 DataTables.net – 第6部分 – 在 AJAX 中返回附加参数
  • ASP.NET8 使用 DataTables.net – 第7部分 – 常规按钮
  • ASP.NET8 使用 DataTables.net – 第8部分 – 选择行
  • ASP.NET8 使用 DataTables.net – 第9部分 – 高级筛选器

 

2 最终结果

本文的目标是创建一个概念验证应用程序,演示 DataTables.net 组件在 AJAX 中返回附加参数。让我们展示本文的结果。

重点是,DataTables.net 组件允许您传递一些附加参数,以便在 AJAX 调用中返回到客户端。我正在表单上显示这些数据。 这些数据是通过 AJAX 调用从后端传递到前端的。

 

3 客户端 DataTables.net 组件

在这里,我将只展示使用 DataTables 组件的 ASP.NET 视图的样子。

<!-- Employees.cshtml -->
<partial name="_LoadingDatatablesJsAndCss" />

@{
    <div class="text-center">
        <h3 class="display-4">Employees table</h3>
    </div>

    <!-- Here is our table HTML element defined. JavaScript library Datatables
    will do all the magic to turn it into interactive component -->
    <table id="EmployeesTable01" class="table table-striped table-bordered ">
    </table>

    <div class="text-center">
        <h6>Passed parameters</h6>
        rParam1: <span id="rParam1"></span> <br />
        rParam2: <span id="rParam2"></span>

    </div>
}

<script>
    // Datatables script initialization=========================================
    // we used defer attribute on jQuery so it might not be available at this point
    // so we go for vanilla JS event

    document.addEventListener("DOMContentLoaded", InitializeDatatable);

    function InitializeDatatable() {
        $("#EmployeesTable01").dataTable({
            //processing-Feature control the processing indicator.
            processing: true,
            //paging-Enable or disable table pagination.
            paging: true,
            //info-Feature control table information display field
            info: true,
            //ordering-Feature control ordering (sorting) abilities in DataTables.
            ordering: true,
            //searching-Feature control search (filtering) abilities
            searching: true,
            //search.return-Enable / disable DataTables' search on return.
            search: {
                return: true
            },
            //autoWidth-Feature control DataTables' smart column width handling.
            autoWidth: true,
            //lengthMenu-Change the options in the page length select list.
            lengthMenu: [10, 15, 25, 50, 100],
            //pageLength-Change the initial page length (number of rows per page)
            pageLength: 10,

            //order-Initial order (sort) to apply to the table.
            order: [[1, 'asc']],

            //serverSide-Feature control DataTables' server-side processing mode.
            serverSide: true,

            //Load data for the table's content from an Ajax source.
            ajax: {
                "url": "@Url.Action("EmployeesDT", "Home")",
                "type": "POST",
                "datatype": "json",
                "dataSrc": extractReturnParameters
            },

            //Set column specific initialization properties
            columns: [
                //name-Set a descriptive name for a column
                //data-Set the data source for the column from the rows data object / array
                //title-Set the column title
                //orderable-Enable or disable ordering on this column
                //searchable-Enable or disable search on the data in this column
                //type-Set the column type - used for filtering and sorting string processing
                //visible-Enable or disable the display of this column.
                //width-Column width assignment.
                //render-Render (process) the data for use in the table.
                //className-Class to assign to each cell in the column.

                {   //0
                    name: 'id',
                    data: 'id',
                    title: "Employee Id",
                    orderable: true,
                    searchable: false,
                    type: 'num',
                    visible: false
                },
                {
                    //1
                    name: 'givenName',
                    data: "givenName",
                    title: "Given Name",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //2
                    name: 'familyName',
                    data: "familyName",
                    title: "Family Name",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //3
                    name: 'town',
                    data: "town",
                    title: "Town",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //4
                    name: 'country',
                    data: "country",
                    title: "Country",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //5
                    name: 'email',
                    data: "email",
                    title: "Email",
                    orderable: true,
                    searchable: true,
                    type: 'string',
                    visible: true
                },
                {
                    //6
                    name: 'phoneNo',
                    data: "phoneNo",
                    title: "Phone Number",
                    orderable: false,
                    searchable: true,
                    type: 'string',
                    visible: true
                }
            ]
        });

        function extractReturnParameters(json) {
            let rParam1 = json.rParam1;
            let rParam2 = json.rParam2;
            //async work
            setTimeout(() => doWorkWithParamters(rParam1, rParam2), 0);
            return json.data;
        }

        function doWorkWithParamters(rParam1, rParam2) {
            let span1 = document.getElementById('rParam1');
            span1.innerHTML = rParam1;
            let span2 = document.getElementById('rParam2');
            span2.innerHTML = rParam2;
        }
    }
</script>

请注意,在 ajax 属性中,我们使用 dataSrc 属性传递对 JavaScript 函数 extractReturnParameters 的引用,该函数将提取返回的参数。

有关这些属性的更多信息,请参阅 [1] 中的手册。这里的应用程序只是 ASP.NET 环境的一个概念验证。

 

4 示例 AJAX 调用

为了更好地理解发生了什么,我使用 Chrome DevTools 捕获了在示例 AJAX 调用中返回的数据。

这是 AJAX 调用响应

{
    "draw": 1,
    "recordsTotal": 1000,
    "recordsFiltered": 1000,
    "data": [
        {
            "id": 459,
            "givenName": "Abbe",
            "familyName": "Crouse",
            "town": "San Jerónimo",
            "country": "Peru",
            "email": "acrousecq@rakuten.co.jp",
            "phoneNo": "590-568-7650"
        },
        {
            "id": 854,
            "givenName": "Abbe",
            "familyName": "Geraldo",
            "town": "Kornyn",
            "country": "Ukraine",
            "email": "ageraldonp@adobe.com",
            "phoneNo": "346-510-7193"
        },
        {
            "id": 726,
            "givenName": "Abigael",
            "familyName": "Davidai",
            "town": "Rukaj",
            "country": "Albania",
            "email": "adavidaik5@blog.com",
            "phoneNo": "750-275-0919"
        },
        {
            "id": 256,
            "givenName": "Adaline",
            "familyName": "Waren",
            "town": "Pruszcz Gdański",
            "country": "Poland",
            "email": "awaren73@netscape.com",
            "phoneNo": "887-568-2194"
        },
        {
            "id": 375,
            "givenName": "Adelaide",
            "familyName": "O'Dowgaine",
            "town": "Fajsławice",
            "country": "Poland",
            "email": "aodowgaineae@networkadvertising.org",
            "phoneNo": "304-825-5438"
        },
        {
            "id": 145,
            "givenName": "Adelheid",
            "familyName": "Fer",
            "town": "Tužno",
            "country": "Croatia",
            "email": "afer40@bravesites.com",
            "phoneNo": "983-283-7629"
        },
        {
            "id": 340,
            "givenName": "Adrian",
            "familyName": "Thunnercliffe",
            "town": "Avelinha",
            "country": "Portugal",
            "email": "athunnercliffe9f@hibu.com",
            "phoneNo": "819-620-4630"
        },
        {
            "id": 585,
            "givenName": "Ag",
            "familyName": "Winchcombe",
            "town": "Tinghir",
            "country": "Morocco",
            "email": "awinchcombeg8@istockphoto.com",
            "phoneNo": "573-856-3366"
        },
        {
            "id": 389,
            "givenName": "Aggy",
            "familyName": "Dacre",
            "town": "Rosignol",
            "country": "Guyana",
            "email": "adacreas@china.com.cn",
            "phoneNo": "941-421-7755"
        },
        {
            "id": 464,
            "givenName": "Aharon",
            "familyName": "Wathall",
            "town": "Mimbaan Timur",
            "country": "Indonesia",
            "email": "awathallcv@bbc.co.uk",
            "phoneNo": "108-340-8110"
        }
    ],
    "rParam1": "My parameter",
    "rParam2": 12345
}

我当然只提取了相关的数据部分。 每一个优秀的 Web 程序员都应该能够从上面的数据中理解发生了什么。

 

5 DataTables.AspNet.Core 库中的错误

不幸的是,C#/.NET 库 DataTables.AspNet.Core 中存在一个与在 AJAX 调用中返回参数相关的错误。 有一个针对该错误的解决方法,我在此示例中使用了它。 这是用于解决该错误的 Helper 类。

using DataTables.AspNet.AspNetCore;
using Newtonsoft.Json;
using System.Collections;

//DataTablesResponseHelper.cs
namespace Example06
{
    /*
     * This code has been taken from https://github.com/ALMMa/datatables.aspnet/issues/72
     * It resolves the bug in library DataTables.AspNet.AspNetCore
     * when returning parameters from server to client
     * proper usage is as follows
     * 
     *  // Create some response additional parameters.
     *   var returnParameters = new Dictionary<string, object>()
     *               {
     *                   { "rParam1", "My parameter" },
     *                   { "rParam2", 12345 }
     *               };
     *
     *  var response = DataTablesResponse.Create(
     *       request, totalRecordsCount, filteredRecordsCount, dataPage, returnParameters);
     *  var response2 = new DataTablesResponseHelper(response);
     *
     *  return new DataTablesJsonResult(response2, true);
     */


    public class DataTablesResponseHelper : DataTables.AspNet.AspNetCore.DataTablesResponse
    {
        protected DataTablesResponseHelper(int draw, string errorMessage) : 
            base(draw, errorMessage)
        {
        }

        protected DataTablesResponseHelper(int draw, string errorMessage, 
            IDictionary<string, object> additionalParameters) : 
            base(draw, errorMessage, additionalParameters)
        {
        }

        protected DataTablesResponseHelper(int draw, int totalRecords, int totalRecordsFiltered, object data) : 
            base(draw, totalRecords, totalRecordsFiltered, data)
        {
        }

        protected DataTablesResponseHelper(int draw, int totalRecords, int totalRecordsFiltered, 
            object data, IDictionary<string, object> additionalParameters) : 
            base(draw, totalRecords, totalRecordsFiltered, data, additionalParameters)
        {
        }

        public DataTablesResponseHelper(DataTablesResponse response) : 
            this(response.Draw, response.TotalRecords, response.TotalRecordsFiltered, 
                response.Data, response.AdditionalParameters)
        {
        }

        private bool IsSuccessResponse()
        {
            return this.Data != null && string.IsNullOrWhiteSpace(this.Error);
        }

        public override string ToString()
        {
            using (StringWriter stringWriter = new StringWriter())
            {
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter((TextWriter)stringWriter))
                {
                    if (this.IsSuccessResponse())
                    {
                        jsonTextWriter.WriteStartObject();
                        jsonTextWriter.WritePropertyName(Configuration.Options.ResponseNameConvention.Draw, true);
                        jsonTextWriter.WriteValue(this.Draw);
                        jsonTextWriter.WritePropertyName(Configuration.Options.ResponseNameConvention.TotalRecords, true);
                        jsonTextWriter.WriteValue(this.TotalRecords);
                        jsonTextWriter.WritePropertyName(Configuration.Options.ResponseNameConvention.TotalRecordsFiltered, true);
                        jsonTextWriter.WriteValue(this.TotalRecordsFiltered);
                        jsonTextWriter.WritePropertyName(Configuration.Options.ResponseNameConvention.Data, true);
                        jsonTextWriter.WriteRawValue(this.SerializeData(this.Data));
                        if (this.AdditionalParameters != null)
                        {
                            foreach (KeyValuePair<string, object> additionalParameter in (IEnumerable<KeyValuePair<string, object>>)this.AdditionalParameters)
                            {
                                jsonTextWriter.WritePropertyName(additionalParameter.Key, true);
                                if (additionalParameter.Value is IEnumerable)
                                {
                                    jsonTextWriter.WriteRawValue(SerializeData(additionalParameter.Value));
                                }
                                else
                                {
                                    jsonTextWriter.WriteValue(additionalParameter.Value);
                                }
                            }
                        }
                        jsonTextWriter.WriteEndObject();
                    }
                    else
                    {
                        jsonTextWriter.WriteStartObject();
                        jsonTextWriter.WritePropertyName(Configuration.Options.ResponseNameConvention.Draw, true);
                        jsonTextWriter.WriteValue(this.Draw);
                        jsonTextWriter.WritePropertyName(Configuration.Options.ResponseNameConvention.Error, true);
                        jsonTextWriter.WriteValue(this.Error);
                        if (this.AdditionalParameters != null)
                        {
                            foreach (KeyValuePair<string, object> additionalParameter in 
                                (IEnumerable<KeyValuePair<string, object>>) this.AdditionalParameters)
                            {
                                jsonTextWriter.WritePropertyName(additionalParameter.Key, true);
                                if (additionalParameter.Value is IEnumerable)
                                {
                                    jsonTextWriter.WriteRawValue(SerializeData(additionalParameter.Value));
                                }
                                else
                                {
                                    jsonTextWriter.WriteValue(additionalParameter.Value);
                                }
                            }
                        }
                        jsonTextWriter.WriteEndObject();
                    }
                    jsonTextWriter.Flush();
                    return stringWriter.ToString();
                }
            }
        }
    }
}

 

6 ASP.NET 后端处理

现在我们来到了 C#/.NET 部分,编写我们的 ASP.NET 代码。 这是我想出的解决方案。 我不会假装这很简单,它假设对 DataTables.AspNet.Core 和 System.Linq.Dynamic.Core 库有很好的理解。

这是代码

//HomeController.cs

//this is target of AJAX call and provides data for
//the table, based on selected input parameters
public IActionResult EmployeesDT(DataTables.AspNet.Core.IDataTablesRequest request)
{
    // There is dependency in this method on names of fields
    // and implied mapping. I see it almost impossible to avoid.
    // At least, in this method, we avoided dependency on the order
    // of table fields, in case order needs to be changed
    //Here are our mapped table columns:
    //Column0 id -> Employee.Id
    //Column1 givenName -> Employee.FirstName
    //Column2 familyName -> Employee.LastName
    //Column3 town -> Employee.City
    //Column4 country -> Employee.Country
    //Column5 email -> Employee.Email
    //Column6 phoneNo -> Employee.Phone

    try
    {
        IQueryable<Employee> employees = MockDatabase.MockDatabase.Instance.EmployeesTable.AsQueryable();

        int totalRecordsCount = employees.Count();

        var iQueryableOfAnonymous = employees.Select(p => new
        {
            id = p.Id,
            givenName = p.FirstName,
            familyName = p.LastName,
            town = p.City,
            country = p.Country,
            email = p.Email,
            phoneNo = p.Phone,
        });

        iQueryableOfAnonymous = FilterRowsPerRequestParameters(iQueryableOfAnonymous, request);

        int filteredRecordsCount = iQueryableOfAnonymous.Count();

        iQueryableOfAnonymous = SortRowsPerRequestParamters(iQueryableOfAnonymous, request);

        iQueryableOfAnonymous = iQueryableOfAnonymous.Skip(request.Start).Take(request.Length);

        var dataPage = iQueryableOfAnonymous.ToList();

        // Create some response additional parameters.
        var returnParameters = new Dictionary<string, object>()
            {
                { "rParam1", "My parameter" },
                { "rParam2", 12345 }
            };

        var response = DataTablesResponse.Create(request, totalRecordsCount, filteredRecordsCount, dataPage, returnParameters);
        var response2 = new DataTablesResponseHelper(response);

        return new DataTablesJsonResult(response2, true);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        var response = DataTablesResponse.Create(request, "Error processing AJAX call on server side");
        return new DataTablesJsonResult(response, false);
    }
}

 

//Program.cs
namespace Example06
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddControllersWithViews();

            // DataTables.AspNet registration 
            DataTablesAspNetRegistration(builder);

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

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

            app.Run();
        }

        //DataTables.AspNet registration
        public static void DataTablesAspNetRegistration(WebApplicationBuilder? builder)
        {
            if (builder == null) { throw new Exception("builder == null"); };

            var options = new DataTables.AspNet.AspNetCore.Options()
               .EnableRequestAdditionalParameters()
               .EnableResponseAdditionalParameters();

            // DataTables.AspNet registration 
            builder.Services.RegisterDataTables(options);
        }
    }
}

 

7 结论

可以下载完整的示例代码项目。

 

8 参考

 

[1] https://datatables.net.cn/

[21] ASP.NET8 使用 DataTables.net – 第1部分 – 基础
https://codeproject.org.cn/Articles/5385033/ASP-NET-8-Using-DataTables-net-Part1-Foundation

[22] ASP.NET8 使用 DataTables.net – 第2部分 – 操作按钮
https://codeproject.org.cn/Articles/5385098/ASP-NET8-using-DataTables-net-Part2-Action-buttons

[23] ASP.NET8 使用 DataTables.net – 第3部分 – 状态保存
https://codeproject.org.cn/Articles/5385308/ASP-NET8-using-DataTables-net-Part3-State-saving

[24] ASP.NET8 使用 DataTables.net – 第4部分 – 多语言
https://codeproject.org.cn/Articles/5385407/ASP-NET8-using-DataTables-net-Part4-Multilingual

[25] ASP.NET8 使用 DataTables.net – 第5部分 – 在 AJAX 中传递附加参数
https://codeproject.org.cn/Articles/5385575/ASP-NET8-using-DataTables-net-Part5-Passing-additi

[26] ASP.NET8 使用 DataTables.net – 第6部分 – 在 AJAX 中返回附加参数
https://codeproject.org.cn/Articles/5385692/ASP-NET8-using-DataTables-net-Part6-Returning-addi

[27] ASP.NET8 使用 DataTables.net – 第7部分 – 常规按钮
https://codeproject.org.cn/Articles/5385828/ASP-NET8-using-DataTables-net-Part7-Buttons-regula

[28] ASP.NET8 使用 DataTables.net – 第8部分 – 选择行
https://codeproject.org.cn/Articles/5386103/ASP-NET8-using-DataTables-net-Part8-Select-rows

[29] ASP.NET8 使用 DataTables.net – 第9部分 – 高级筛选器
https://codeproject.org.cn/Articles/5386263/ASP-NET8-using-DataTables-net-Part9-Advanced-Filte

 

 

© . All rights reserved.