locked
Getting System.ArgumentNullException trying to pass model from view to controller RRS feed

  • Question

  • User-1849651236 posted

    Hello,

    I have an Asp.Net Core 2.1, MVC, C# Web application in Visual Studio 2017 15.7.5.

    I am trying to pass a model from a view to a controller using an $.ajax call.  It gets to the controller but an error occurs saying: "System.ArgumentNullException: 'Value cannot be null.'" on the first line in the ProductsController.

    All of the code came from reading other forum articles about how to accomplish sending a model to a controller using an ajax call.

    Here is my code:

    ProductsController.cs:

    public ActionResult DeleteProducts(string myModel)
              {
                   List<ProductViewModel> prods = JsonConvert.DeserializeObject<List<ProductViewModel>>(myModel);
                   return View("~/Views/API/AccessToken.cshtml", myModel);
              }

    Defualt.cshtml:

    @model List<ChinavasionAPI.Models.CAPIViewModels.ProductViewModel>
    @using Microsoft.AspNetCore.Http.Extensions
    @{
         ViewData["Title"] = "products";
    
    }
    
    @section Scripts {
         <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    }
    
    <h2>Products List</h2>
    
    <div class="container-fluid">
         <div>
              <button class="btn btn-default" id="del-products-button" value="Delete Products" onclick="delProductsTask()">Delete Products</button>
         </div>
         <table class="table table-hover table-bordered table-striped">
              <thead>
                   <tr>
                        <th colspan="2" scope="colgroup">Lakeside products  =  @Model.Count.ToString()</th>
                        <th></th>
                        <th colspan="2" scope="colgroup">Chinavasion products  =  @ViewData["ChvProductCount"]<br />Chinavasion products not found  =  @ViewData["ChvProductNotFoundCount"]</th>
                   </tr>
                   <tr>
                        <th>Product ID</th>
                        <th>Sku</th>
                        <th></th>
                        <th>Product ID</th>
                        <th>Model Code</th>
                   </tr>
              </thead>
              <tbody>
                   @foreach (var item in Model)
                   {
                        <tr>
                             <td><span>@item.Id</span></td>
                             <td><span>@item.Sku</span></td>
                             <td><span></span></td>
                             <td><span>@item.product_id</span></td>
                             <td><span>@item.model_code</span></td>
                        </tr>
                   }
              </tbody>
         </table>
    </div>
    <script>
    
    function delProductsTask() {
         var viewModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model, Newtonsoft.Json.Formatting.Indented));
         $.ajax({
              type: 'GET',
              dataType: 'json',
              cache: false,
              url: '/Products/DeleteProducts',
              data: viewModel,
              success: function (data, textStatus, jqXHR) {
                   //Do Stuff 
                   $(".productslist").html(data.Id);
              },
              error: function (jqXHR, textStatus, errorThrown) {
                   //Do Stuff or Nothing
              }
         });
    }
    
    </script>

    ProductViewModel:

    namespace ChinavasionAPI.Models.CAPIViewModels
    {
         public class ProductViewModel
         {
    
              public string Id { get; set; }
              public string Sku { get; set; }
              public int? product_id { get; set; }
              public string model_code { get; set; }
    
         }
    }
    

    Thanks,
    Tony

    Monday, July 30, 2018 9:20 PM

Answers

  • User1724605321 posted

    Hi TGirgenti,

    You should pass Json string to controller :

         var viewModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model, Newtonsoft.Json.Formatting.Indented));
         $.ajax({
              type: 'GET',
              dataType: 'json',
              cache: false,
             url: '/Products/DeleteProducts?myModel=' + JSON.stringify(viewModel),
    
              success: function (data, textStatus, jqXHR) {
                   //Do Stuff
                   $(".productslist").html(data.Id);
              },
              error: function (jqXHR, textStatus, errorThrown) {
                   //Do Stuff or Nothing
              }
         });

    I would suggest you not to post entire viewmodel lists to controller , just pass ids and delete records by ids on sever side .

    Best Regards,

    Nan Yu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, July 31, 2018 7:01 AM
  • User1724605321 posted

    Hi TGirgenti ,

    When I try your method, it never gets to the DeleteProducts method.

    That works on my environment . Please debug your application and use browser's developer tool or fiddle to trace the request and check the detailed error .

    Or use :

     $.ajax({
              type: 'GET',
              dataType: 'json',
             data: { myModel: JSON.stringify(viewModel) },
             url: '/Home/DeleteProducts',
    
              success: function (data, textStatus, jqXHR) {
                   //Do Stuff
                   $(".productslist").html(data.Id);
              },
              error: function (jqXHR, textStatus, errorThrown) {
                   //Do Stuff or Nothing
              }
         });

    That's a very good idea.  How would I do that?  Should I pass a list of IDs?

    You can pass an array object include each id , or string include each id and split by comma to server side . To get ids of each row , you can firstly add class to span :

      <td><span class="rowID">@item.Id</span></td>

    And get ids by :

            $(".rowID").each(function () {
                alert($(this).html());
            });

    Best Regards,

    Nan Yu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, August 1, 2018 6:12 AM

All replies

  • User1724605321 posted

    Hi TGirgenti,

    You should pass Json string to controller :

         var viewModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model, Newtonsoft.Json.Formatting.Indented));
         $.ajax({
              type: 'GET',
              dataType: 'json',
              cache: false,
             url: '/Products/DeleteProducts?myModel=' + JSON.stringify(viewModel),
    
              success: function (data, textStatus, jqXHR) {
                   //Do Stuff
                   $(".productslist").html(data.Id);
              },
              error: function (jqXHR, textStatus, errorThrown) {
                   //Do Stuff or Nothing
              }
         });

    I would suggest you not to post entire viewmodel lists to controller , just pass ids and delete records by ids on sever side .

    Best Regards,

    Nan Yu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, July 31, 2018 7:01 AM
  • User-1849651236 posted

    Nan Yu,

    When I try your method, it never gets to the DeleteProducts method.

    I would suggest you not to post entire viewmodel lists to controller , just pass ids and delete records by ids on sever side .

    That's a very good idea.  How would I do that?  Should I pass a list of IDs?

    Thanks,
    Tony

    Tuesday, July 31, 2018 11:30 AM
  • User1724605321 posted

    Hi TGirgenti ,

    When I try your method, it never gets to the DeleteProducts method.

    That works on my environment . Please debug your application and use browser's developer tool or fiddle to trace the request and check the detailed error .

    Or use :

     $.ajax({
              type: 'GET',
              dataType: 'json',
             data: { myModel: JSON.stringify(viewModel) },
             url: '/Home/DeleteProducts',
    
              success: function (data, textStatus, jqXHR) {
                   //Do Stuff
                   $(".productslist").html(data.Id);
              },
              error: function (jqXHR, textStatus, errorThrown) {
                   //Do Stuff or Nothing
              }
         });

    That's a very good idea.  How would I do that?  Should I pass a list of IDs?

    You can pass an array object include each id , or string include each id and split by comma to server side . To get ids of each row , you can firstly add class to span :

      <td><span class="rowID">@item.Id</span></td>

    And get ids by :

            $(".rowID").each(function () {
                alert($(this).html());
            });

    Best Regards,

    Nan Yu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, August 1, 2018 6:12 AM
  • User-1849651236 posted

    Nan Yu,

    I did get the ajax call to work.  I forgot to take out the "data:" parameter line.  That was my problem.  It works fine now.

    Also, thanks for your help with the array of ids issue.

    Your expertise is very much appreciated.

    Thanks,
    Tony

    Wednesday, August 1, 2018 12:42 PM