How to pass either a JavaScript array or JSON string to an Asp .NET Core 6 MVC controller using AJAX

Sherpa 306 Reputation points
2024-08-27T02:16:59.68+00:00

I am working on an Asp.Net Core 6 MVC project. Initially, I tried to send a javascript array created by this line of code,

var reportData = $('#reportForm').serializeArray();

to the controller. The controller signature was

public async Task<string> ProcessReport(ReportsConfigurationVM reportsConfigurationVM).

However, all the properties of the object reportsConfigurationVM had null values. So, I have converted the javascript array to a string by the following code:

var dataToPost = JSON.stringify(reportData);

and changed the controller signature to receive a string value.

public async Task<string> ProcessReport([FromBody] string reportsConfigurationVM)

However, the string "reportsConfigurationVM" in the above code came out as null. When I checked the value of dataToPost in the view, it was a valid JSON object as shown below:

[{"name":"CustomerNumber","value":"12345"},{"name":"Year","value":"2024"},{"name":"__RequestVerificationToken","value":"CfDJ8PVSsilBiOxCixGgY8TVnJlM-gjOWKMAq7GwBeOfy_fQvqz1-jXnHLEAaA5yHblnxH1aI7GQUR4PHGIK0SgqmJRjUG3ePL-lzQdMlKGUPWFICQq8ZbmVOYend3dWdHKzauvfm-eKCCt79Zn1Ve00OIg"}]

If you could please help me to successfully pass either a JS array or a JSON string to the controller, from the view through an AJAX call that would be a great help.

Controller Code:
[HttpPost]
public async Task<string> ProcessReport([FromBody] string  reportsConfigurationVM)
{
    
    
        List<RiskByYearTest> myList = new List<RiskByYearTest>();
    	RiskByYearTest r1 = new RiskByYearTest();
    	r1.CustomerNumber = "4549601";
    	r1.CustomerStatus = "Active";
    	r1.StartYear = "2022";

    	RiskByYearTest r2 = new RiskByYearTest();
    	r2.CustomerNumber = "4549602";
    	r2.CustomerStatus = "Closed";
    	r2.StartYear = "2023";
    	myList.Add(r1);
    	myList.Add(r2);

    	return JsonConvert.SerializeObject(myList);
    
    
    
}

Model:
public class ReportsConfigurationVM
{
public string? CustomerNumber { get; set; }
public string? Date1 { get; set; }
public string? Date2 { get; set; }
[Required(ErrorMessage = "Year is required")]        
public string? Year { get; set; }
public int UserID { get; set; }
}

Index.cshtml:
@model ViewModels.ReportsConfigurationVM

<div class="display-area ">
   
    <div style="padding-top: 10px; padding-left: 5px">
        <form id="reportForm" method="post">
            
            <div asp-validation-summary="All" class="text-danger" style="text-align:left"></div>
            <div class="card" style="width: 18rem;height: auto;width:800px ">
                <div class="card-header">
                    Available Reports
                </div>
                <div class="form-floating register-input">
                    <!-- input  -->
                    <input id="Year" placeholder="editlabel" asp-for="Year" class="form-control" />
                    <!-- label  -->
                    <label>Enter Year</label>
                    <!-- required -->
                    <span asp-validation-for="Year" class="text-danger"></span>
                </div>
            
        </div>
    </div>
   </form>
   <div style="padding-top: 20px; padding-bottom:20px">
    <button class="btn btn-lg btn-primary" onclick="javascript:runReport();">Run Report</button>
    <button id="clear" class="btn btn-lg btn-secondary">Clear Filters</button>
   </div>
<script>
    
    function runReport() {
        
        var reportData;
         
        var dataToPost
        
        var dataTableOptions = {
            "paging": true,
            "lengthChange": false,
            "searching": false,
            "ordering": true,
            "info": true,
            "autoWidth": false,
            "responsive": true,
            "columnDefs": "",
            
            "ajax": {
                url: "/Reports/ProcessReport",
                type: "POST",
                data: dataToPost,
                contentType: "application/json; charset=utf-8",
                dataType: 'JSON',                    
                // traditional: true,                    
                "error": function (e) {
                    console.log(e);
                },
                "dataSrc": '',
                
            },
            "columns": [
                { "data": "CustomerNumber", "name": "CustomerNumber", "autoWidth": true},
                { "data": "CustomerStatus", "name": "CustomerStatus", "autoWidth": true },
                { "data": "StartYear", "name": "StartYear", "autoWidth": true }
            ],


        }
        
        reportData = $('#reportForm').serializeArray();
        dataToPost = JSON.stringify(reportData);
        //alert(typeof (dataToPost)); //Type turns out to be a JSON string
        var myDataTable = $('#riskReport').DataTable(dataTableOptions);
        
    }

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,609 questions
ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,506 questions
0 comments No comments
{count} votes

Accepted answer
  1. JasonPan - MSFT 5,906 Reputation points Microsoft Vendor
    2024-08-27T08:30:23.1633333+00:00

    Hi @Sherpa,

    I found you are using DataTable javascript library in your project, and I believe you can pass the data successfully by using basic ajax method(like the sample SurferOnWww shared).

    And I following your sample code and make it work in my side. Please kindly check the data area under the DataTable/ajax like below. Hope it can help you.

    Reports/Index.cshtml

    @model ReportDemo.Models.ReportsConfigurationVM
    
    <div class="display-area">
        <div style="padding-top: 10px; padding-left: 5px">
            <form id="reportForm" method="post">
                <div asp-validation-summary="All" class="text-danger" style="text-align:left"></div>
                <div class="card" style="width: 18rem;height: auto;width:800px ">
                    <div class="card-header">
                        Available Reports
                    </div>
                    <div class="form-floating register-input">
                        <!-- input  -->
                        <input id="Year" name="Year" placeholder="Enter Year" asp-for="Year" class="form-control" />
                        <!-- label  -->
                        <label>Enter Year</label>
                        <!-- required -->
                        <span asp-validation-for="Year" class="text-danger"></span>
                        
                    </div>
                </div>
            </form>
        </div>
        <div style="padding-top: 20px; padding-bottom:20px">
            <button class="btn btn-lg btn-primary" onclick="javascript:runReport();">Run Report</button>
            <button id="clear" class="btn btn-lg btn-secondary">Clear Filters</button>
        </div>
    </div>
    <script>
        function runReport() {
            $('#riskReport').DataTable({
                "paging": true,
                "lengthChange": false,
                "searching": false,
                "ordering": true,
                "info": true,
                "autoWidth": false,
                "responsive": true,
                "ajax": {
                    url: "/Reports/ProcessReport",
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    dataType: 'json',
                    data: function(d) {
                        var reportDataArray = $('#reportForm').serializeArray();
                        var reportDataObj = {};
                        $.each(reportDataArray, function(index, field) {
                            reportDataObj[field.name] = field.value;
                        });
            
                        return JSON.stringify(reportDataObj); 
                    },
                    "dataSrc": ''
                },
                "columns": [
                    { "data": "customerNumber", "name": "CustomerNumber", "autoWidth": true },
                    { "data": "customerStatus", "name": "CustomerStatus", "autoWidth": true },
                    { "data": "startYear", "name": "StartYear", "autoWidth": true }
                ]
            })
        }
    </script>
    <table id="riskReport" class="display" style="width:100%">
        <thead>
            <tr>
                <th>Customer Number</th>
                <th>Customer Status</th>
                <th>Start Year</th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>
    

    ProcessReport method

    [HttpPost]
    public async Task<IActionResult> ProcessReport([FromBody] ReportsConfigurationVM reportsConfigurationVM)
    {
        if (reportsConfigurationVM == null)
        {
            return BadRequest("Error: Model binding failed. The model is null.");
        }
        List<RiskByYearTest> myList = new List<RiskByYearTest>
        {
            new RiskByYearTest { CustomerNumber = "4549601", CustomerStatus = "Active", StartYear = "2022" },
            new RiskByYearTest { CustomerNumber = "4549602", CustomerStatus = "Closed", StartYear = "2023" }
        };
        return Ok(myList);
    }
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    Jason

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. SurferOnWww 3,041 Reputation points
    2024-08-27T06:06:03.1133333+00:00

    When I checked the value of dataToPost in the view, it was a valid JSON object as shown below: [{"name":"CustomerNumber","value":"12345"},{"name":"Year","value":"2024"}, ...

    Since the resultant JSON string is not proper the model binding to the argument of ProcessReport method could not be done. The JSON string must be like as follows;

    {"CustomerNumber":"12345","Date1":"8/20","Date2":"8/27","Year":"2024","UserID":1}
    

    Use $('#reportForm').serialize(); instead of $('#reportForm').serializeArray(); to send the form data in the application/x-www-form-urlencoded format.

    Shown below is a sample code:

    Controller and Model

    using Microsoft.AspNetCore.Mvc;
    using MvcNet8App.Models;
    using System.ComponentModel.DataAnnotations;
    using System.Diagnostics;
    
    namespace MvcNet8App.Controllers
    {
        public class HomeController : Controller
        {
            private readonly ILogger<HomeController> _logger;
    
            public HomeController(ILogger<HomeController> logger)
            {
                _logger = logger;
            }
    
            public IActionResult Index()
            {
                return View();
            }
    
    
            public IActionResult ProcessReport()
            {
                var model = new ReportsConfigurationVM
                {
                    CustomerNumber = "12345",
                    Date1 = "8/20",
                    Date2 = "8/27",
                    Year = "2024",
                    UserID = 1
                };
                return View(model);
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public IActionResult ProcessReport(ReportsConfigurationVM reportsConfigurationVM)
            {
                if (ModelState.IsValid)
                {               
                    return RedirectToAction("Index", "Home");
                }
                return View(reportsConfigurationVM);
            }
        }
    
        public class ReportsConfigurationVM
        {
            public string? CustomerNumber { get; set; }
            public string? Date1 { get; set; }
            public string? Date2 { get; set; }
            [Required(ErrorMessage = "Year is required")]
            public string? Year { get; set; }
            public int UserID { get; set; }
        }
    }
    

    View

    @model MvcNet8App.Controllers.ReportsConfigurationVM
    
    @{
        ViewData["Title"] = "ProcessReport";
    }
    
    <h1>ProcessReport</h1>
    
    <hr />
    <div class="row">
        <div class="col-md-4">
            <form id="form1" asp-action="ProcessReport">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="CustomerNumber" class="control-label"></label>
                    <input asp-for="CustomerNumber" class="form-control" />
                    <span asp-validation-for="CustomerNumber" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Date1" class="control-label"></label>
                    <input asp-for="Date1" class="form-control" />
                    <span asp-validation-for="Date1" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Date2" class="control-label"></label>
                    <input asp-for="Date2" class="form-control" />
                    <span asp-validation-for="Date2" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Year" class="control-label"></label>
                    <input asp-for="Year" class="form-control" />
                    <span asp-validation-for="Year" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="UserID" class="control-label"></label>
                    <input asp-for="UserID" class="form-control" />
                    <span asp-validation-for="UserID" class="text-danger"></span>
                </div>
    
                <div class="form-group">
                    <input id="button1" type="button" value="Ajax Upload" />
                </div>
            </form>
        </div>
    </div>
    
    @section Scripts {
        @{
            await Html.RenderPartialAsync("_ValidationScriptsPartial");
    
            <script type="text/javascript">
                //<![CDATA[
               
                $("#button1").on("click", function () {
                    var formUrlEncoded = $("#form1").serialize();
    
                    $.ajax({
                        type: "POST",
                        url: "/Home/ProcessReport",
                        data: formUrlEncoded,
                        success: function (data) {
                           
                        },
                        error: function (jqXHR, status, error) {
                            
                        }
                    });
                })
    
                //]]>
            </script>
        }
    }
    

    Result

    enter image description here

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.