Search code examples
javascriptc#datatablesasp.net-core-mvcasp.net-core-2.1

ASP.Net Core 2.1 with DataTable.net datatables is not displaying any data


I have an ASP.Net Core 2.1 MVC website and I am trying to get Datatables.net implemented in an index page to display a list of users. I am also following the process in this c-sharpcorner post.

The datatable is displaying on my page but it does not contain any data in the rows. It is getting the totalRecords count but it is having a problem with the data returned from the ajax call to my controller.

I can see in my controller that it is returning the json data payload populated with the data from my database. So it appears to be an issue with the data as defined in the javascript for the page.

When the page loads, I get this popup.

Datatable error

However, when I examine the data payload in the controller action response, I can see the valid data, including the CompanyId value of each record. I reviewed the troubleshooting in the link provided in the popup dialog box but it seems from that resource, I am doing everything correctly.

Here is my index.cshtml

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}


<div class="bg-color-off-white">

    <div class="container pb-5">
        <div class="row">
            <div class="col-2 mt4">
                <h2>@ViewData["Title"]</h2>
            </div>
            <div class="col-10 mt4">
                <a class="fr" asp-area="" asp-page="/Users/CreateUser">Create New User</a>
            </div>
        </div>
        <div class="row">
            <div class="col-12">
                <section class="border border-dark rounded">

                    <table id="userlist" class="table table-sm table-striped table-bordered dt-responsive nowrap" witth="100%">
                        <thead>
                            <tr class="table-secondary">
                                <th class="pl-2">CompanyId</th>
                                <th>FirstName</th>
                                <th>LastName</th>
                                <th>UserName</th>
                                <th>Email</th>
                                <th class="text-center">EmailConfirmed</th>
                                <th>PhoneNumber</th>
                                <th>IsEnabled</th>
                                <th>Edit</th>
                            </tr>
                        </thead>

                    </table>

                </section>

            </div>
        </div>
    </div>
</div>



@section Scripts{

    <partial name="_DataTableScriptsPartial" />

    <script>

        $(document).ready(function () {
            $("#userlist").DataTable({
                "processing": true, // for show progress bar
                "serverSide": true, // for process server side
                "filter": true, // this is for disable filter (search box)
                "orderMulti": false, // for disable multiple column at once
                "ajax": {
                    "url": "/Accounts/LoadData",
                    "type": "POST",
                    "datatype": "json"
                },
                "columns": [
                    { "data": "CompanyId", "name": "CompanyId", "autoWidth": true },
                    { "data": "FirstName", "name": "FirstName", "autoWidth": true },
                    { "data": "LastName", "name": "LastName", "autoWidth": true },
                    { "data": "UserName", "name": "UserName", "autoWidth": true },
                    { "data": "Email", "name": "Email", "autoWidth": true },
                    { "data": "EmailConfirmed", "name": "EmailConfirmed", "autoWidth": true },
                    { "data": "PhoneNumber", "name": "PhoneNumber", "autoWidth": true },
                    { "data": "IsEnabled", "name": "IsEnabled", "autoWidth": true },
                    {
                        "render": function (data, type, full, meta) { return `<a class="btn btn-info" href="/DemoGrid/Edit/${full.UserName}">Edit</a>`; }
                    }
                ]

            });
        });
    </script>
}

and here is my controller method

    public IActionResult LoadData()
    {
        try
        {
            var draw = HttpContext.Request.Form["draw"].FirstOrDefault();
            var start = Request.Form["start"].FirstOrDefault();
            var length = Request.Form["length"].FirstOrDefault();
            var sortColumn = Request.Form["columns[" + Request.Form["order[0][column]"].FirstOrDefault() + "][name]"].FirstOrDefault();
            var sortColumnDirection = Request.Form["order[0][dir]"].FirstOrDefault();
            var searchValue = Request.Form["search[value]"].FirstOrDefault();
            var pageSize = length != null ? Convert.ToInt32(length) : 0;
            var skip = start != null ? Convert.ToInt32(start) : 0;
            var recordsTotal = 0;
            var userData = (from tempUser in _context.Users select tempUser);

            //var userData = _context.Users.ToList();

            //if (!(string.IsNullOrEmpty(sortColumn) && string.IsNullOrEmpty(sortColumnDirection)))
            //{
            //    userData = userData.OrderBy(sortColumn + " " + sortColumnDirection);
            //}

            if (!string.IsNullOrEmpty(searchValue))
            {
                userData = userData.Where(m => m.LastName == searchValue);
            }

            recordsTotal = userData.Count();
            var data = userData.Skip(skip).Take(pageSize).ToList();
            return Json(new
            {
                draw = draw,
                recordsFiltered = recordsTotal,
                recordsTotal = recordsTotal,
                data = data
            });

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            throw;
        }
    }

If I set a breakpoint after the line... var data = userData.Skip(skip).Take(pageSize).ToList(); in my controller action method, I can see that the data property in the JSON payload is correctly populated with data from my database.

Data object populated with data

_context.Users is the ASP.Net Core 2.1 Identity generated table based upon ApplicationUser, which is in turn based on IdentityUser. It has more properties than I am referencing in the javascript for DataTable but I do not see on the Datatable.net site where you cannot have more columns in the data source than are defined in the Columns array for Datatable, so I have to assume that is not the issue.

I believe that the response is being read by the ajax call in the Datatable javascript because I can see that the total number of records and the page number are set, as well as the number of rows shown in the list. It is just missing the actual row data.

DataTable shown on Accounts Page

So it is most likely some issue with how I am retrieving the actual data property o the response in the javascript. But so far, I am not able to figure out why.

It is probably something minor but I am fairly new to javascript so it is just not obvious to me yet.

Any ideas?


Solution

  • Most likely you are getting camel case json back from the server. This is often set as the default. Use your DevTools to check what the response is that you are getting back from the server and verify that your data properties are coming through with the expected casing. Likely your CompanyId property is being redered in json as companyId.

    If you are dealing with this situation and you don't want to adjust your client side property names from those of your serialized server side classes you can add some configuration in your startup that looks something like this...

    public void ConfigureServices(IServiceCollection services)
    {
         services.AddJsonOptions(options => {
                        var resolver = options.SerializerSettings.ContractResolver;
                        if (resolver != null)
                        {
                            var res = (DefaultContractResolver)resolver;
                            res.NamingStrategy = null;
                        }
                    });
    }
    

    The above code will cause the dot net core to not mess with the naming convention of your classes.

    You can read some more about resolvers at https://dotnetcoretutorials.com/2018/05/05/setting-json-serialization-configuration-at-runtime-on-a-net-core-api/