ajaxasp.net-coredatatableshttp-status-code-400asp.net-apicontroller

jQuery DataTables warning: table id={id} Ajax error status code 400 in ASP.NET Core project


I am trying to use jQuery Datatables in my ASP.NET Core project. My Controller class has the following code:

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    private readonly IUsersService usersService;

    public UsersController(IUsersService usersService)
    {
        this.usersService = usersService;
    }

    [HttpPost("GetUsers")]
    public IActionResult GetUsers()
    {
        try
        {
            var draw = this.Request.Form["draw"].FirstOrDefault();
            var start = this.Request.Form["start"].FirstOrDefault();
            var length = this.Request.Form["length"].FirstOrDefault();
            var sortColumn = this.Request.Form["columns[" + this.Request.Form["order[0][column]"].FirstOrDefault() + "][name]"].FirstOrDefault();
            var sortColumnDirection = this.Request.Form["order[0][dir]"].FirstOrDefault();
            var searchValue = this.Request.Form["search[value]"].FirstOrDefault();
            int pageSize = length != null ? Convert.ToInt32(length) : 0;
            int skip = start != null ? Convert.ToInt32(start) : 0;
            int recordsTotal = 0;

            var userData = this.usersService.GetUsersData(sortColumn, sortColumnDirection, searchValue);

            recordsTotal = userData.Count();

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

            return this.Ok(jsonData);
        }
        catch (Exception e)
        {
            throw;
        }
    }
}

I inject IUsersService which has the following method:

public IEnumerable<ApplicationUser> GetUsersData(string sortColumn, string sortColumnDirection, string searchValue)
    {
        var users = this.usersRepository.All();
        var userData = from user in users select user;

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

        if (!string.IsNullOrEmpty(searchValue))
        {
            userData = userData.Where(s => s.FirstName.Contains(searchValue)
                                || s.MiddleName.Contains(searchValue)
                                || s.LastName.Contains(searchValue)
                                || s.BirthDate.ToShortDateString().Contains(searchValue)
                                || s.Gender.ToString().Contains(searchValue)
                                || s.PhoneNumber.Contains(searchValue));
        }

        return userData;
    }

My Index.cshtml file is the following:

@{
    this.ViewData["Title"] = "Home Page";
}

<link href="~/lib/datatables.net-bs5/dataTables.bootstrap5.min.css" rel="stylesheet" />

<div class="container-fluid">
    <br />
    <div style="width:90%; margin:0 auto;">
        <table id="usersTable" class="table table-striped table-bordered dt-responsive nowrap"
               width="100%" cellspacing="0">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>@GlobalConstants.FirstName</th>
                    <th>@GlobalConstants.MiddleName</th>
                    <th>@GlobalConstants.LastName</th>
                    <th>@GlobalConstants.BirthDate</th>
                    <th>@GlobalConstants.Gender</th>
                    <th>@GlobalConstants.PhoneNumber</th>
                </tr>
            </thead>
        </table>
    </div>
</div>
@section Scripts
{
    <script src="~/lib/datatables.net/jquery.dataTables.min.js"></script>
    <script src="~/lib/datatables.net-bs5/dataTables.bootstrap5.min.js"></script>
    <script src="~/js/usersTable.js"></script>
}

My usersTable.js includes the following code:

$(document).ready(function () {
    $("#usersTable").DataTable({
        "processing": true,
        "serverSide": true,
        "filter": true,
        "ajax": {
            "url": "/api/Users/GetUsers",
            "type": "POST",
            "datatype": "json"
        },
        "columnDefs": [{
            "targets": [0],
            "visible": false,
            "searchable": false
        }],
        "columns": [
            { "data": "id", "name": "Id", "autoWidth": true },
            { "data": "firstName", "name": "First Name", "autoWidth": true },
            { "data": "middleName", "name": "Middle Name", "autoWidth": true },
            { "data": "lastName", "name": "Last Name", "autoWidth": true },
            { "data": "birthDate", "name": "Birth Date", "autoWidth": true },
            { "data": "gender", "name": "Gender", "autoWidth": true },
            { "data": "phoneNumber", "name": "Phone Number", "autoWidth": true },
        ]
    });
});

When I start the application I receive the following error: "DataTables warning: table id=usersTable - Ajax error. For more information about this error, please see http://datatables.net/tn/7". The error status code is 400. I tried debugging the app and I noticed that my breakpoint in the beginning of the GetUsers() method in the ApiController is never reached. What am I doing wrong? I have searched a lot for different solutions in different forums but nothing seems to work for me. I am new to this so I am probably missing something. Please, help!


Solution

    1. Make sure that your API rout is correct and accessible

    2. Put this line in your Razor view:

      @Html.AntiForgeryToken()
      
    3. Add this config to your startup or program (.net 6) class

      services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
      
    4. In the DataTable JS configuration, add this config:

       "ajax": {
           "url": "/api/Users/GetUsers",
           "beforeSend": function (xhr) {
               xhr.setRequestHeader("XSRF-TOKEN",
                  $('input:hidden[name="__RequestVerificationToken"]').val());
            },
            "type": "POST",
            "datatype": "json"
        },