0

I execute a jQuery $.ajax function in a asp.net partial view to call a controller action method to set a session variable.

I stringify the var object I create.

If I use:

contentType: "application/json",

it does NOT go into the controller action method, but the

 success: function

returns an alert.

enter image description here

My console log shows the objects properties have values.

enter image description here

Why does it not go into the controller action method?


In this scenario, if I use:

contentType: "application/x-www-form-urlencoded; charset=UTF-8",

it does go into the controller action method, but the argument it receives is NULL

enter image description here

yet my console log shows the objects properties have values. And the

 success: function

returns an alert.

Why is the input parameter a null?


The partial view:

@model GbngWebClient.Models.LikeOrDislikeVM

<style>
.fa {
    cursor: pointer;
    user-select: none;
}

    .fa:hover {
        color: blue;
    }

/* I added. */
.my-size {
    font-size: 20px;
}

.my-button {
    border: none;
    padding: 8px 10px;
     /* To make the buttons stay on the same line. */
    float: left;
    font-size: 16px;
    margin: 4px 2px;
    background-color: white;
}
</style>

<div class="row">
<div>
    <button class="blogLike my-button fa fa-thumbs-up"><span class="my-size, likeCount"> : @Model.LikeCount </span></button>
    <button class="blogDisLike my-button fa fa-thumbs-down"><span class="my-size, dislikeCount"> : @Model.DisLikeCount</span></button>
</div>
</div>

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Styles.Render("~/Content/css")

<script type="text/javascript">
$(document).ready(function () {
    // For testing:
    console.log('Here at ready. ');

    // JavaScript needs it as 'false'. So using these 'const' to convert them.
    const False = false, True = true;

    // Set the disabled attributes and color.
    SetLike(@Model.LikeDisabled);
    SetDisLike(@Model.DisLikeDisabled);

    // Create the variable in the image of the LikeOrDislikeVM view model.
    var holdLikeOrDislikeVM = {
        BlogId : @Model.BlogId,
        UserId: @Model.UserId,
        LikeCount: @Model.LikeCount,
        DisLikeCount: @Model.DisLikeCount,
        LikeDisabled: @Model.LikeDisabled,
        DisLikeDisabled: @Model.DisLikeDisabled,
    };

    console.log("hold: " + holdLikeOrDislikeVM.BlogId);
    console.log("hold: " + holdLikeOrDislikeVM.UserId);
    console.log("hold: " + holdLikeOrDislikeVM.LikeCount);
    console.log("hold: " + holdLikeOrDislikeVM.DisLikeCount);
    console.log("hold: " + holdLikeOrDislikeVM.LikeDisabled);
    console.log("hold: " + holdLikeOrDislikeVM.DisLikeDisabled);

    $.ajax({
        type: 'POST',
        url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
        data: { likeOrDislikeVM: JSON.stringify(holdLikeOrDislikeVM) },
        //contentType: "application/x-www-form-urlencoded; charset=UTF-8",
        contentType: "application/json",
        success: function (response) {
            alert("Success. Response: " + response);
        },
        error: function (xhr, ajaxOptions, thrownError) {
            alert("Critical Error: something is wrong in the call to SetModelSessionVar! Status: " + xhr.status + ". Error: " + thrownError.toString() + ". Response Text: " + xhr.responseText);
        }
    })
                  

    //--------------------------------------------------------------------------------------
    // Set the disabled attribute to true or false.
    //--------------------------------------------------------------------------------------
    function SetLike(disabledSwitch) {
        // For testing:
        console.log('Here at Setlike. ' + disabledSwitch);

        $(".blogLike").attr('disabled', disabledSwitch);

        if (disabledSwitch == true )
        {
            // Show by color that it was previously liked.
            $(".blogLike").css('color', 'green');
        }

        if (disabledSwitch == false)
        {
            // Show by color that it can be clicked.
            $(".blogLike").css('color', 'black');
        }
    }

    //--------------------------------------------------------------------------------------
     // Set the disabled attribute to true or false.
    //--------------------------------------------------------------------------------------
    function SetDisLike(disabledSwitch) {
        // For testing:
        console.log('Here at SetDisLike. ' + disabledSwitch);

        $(".blogDisLike").attr('disabled', disabledSwitch);

        if (disabledSwitch == true)
        {
            // Show by color that it was previously disliked.
            $(".blogDisLike").css('color', 'green');
        }

        if (disabledSwitch == false)
        {
          // Show by color that it can be clicked.
            $(".blogDisLike").css('color', 'black');
        }
    }
});
</script>

The view model:

namespace GbngWebClient.Models
{
    public class LikeOrDislikeVM
    {
        public int BlogId { get; set; }
        public int UserId { get; set; }
        public int LikeCount { get; set; }
        public int DisLikeCount { get; set; }
        public bool LikeDisabled { get; set; }
        public bool DisLikeDisabled { get; set; }
    }
}

The controller actions method:

[HttpPost]
public void SetModelSessionVar(LikeOrDislikeVM likeOrDislikeVM)
{
   // Sets a model session variable according to the argument passed in.
   Session["likeOrDislikeVM"] = likeOrDislikeVM;
}

Per discussions with freedomn-m, I discovered:

For a controller action method of:

[HttpPost]
public void SetModelSessionVar(string likeOrDislikeVM)
{
   Session["likeOrDislikeVM"] = likeOrDislikeVM;
}

This is the only 1 that works (comes into the controller method as: {"BlogId":40,"UserId":3,"LikeCount":0,"DisLikeCount":1,"LikeDisabled":false,"DisLikeDisabled":true}):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: { likeOrDislikeVM: JSON.stringify(holdLikeOrDislikeVM) },
     contentType: "application/x-www-form-urlencoded; charset=UTF-8",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 })

Does not work (comes into the controller method as: null):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: JSON.stringify(holdLikeOrDislikeVM),
     contentType: "application/json",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 })

Does not work (comes into the controller method as: null):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: JSON.stringify(holdLikeOrDislikeVM),
     contentType: "application/x-www-form-urlencoded; charset=UTF-8",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 })

Does not work (does not come into the controller method and nothing in console shown):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: { likeOrDislikeVM: JSON.stringify(holdLikeOrDislikeVM)},
     contentType: "application/json",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 })

Now for a controller action method of:

[HttpPost]
public void SetModelSessionVar(LikeOrDislikeVM likeOrDislikeVM)
{
   Session["likeOrDislikeVM"] = likeOrDislikeVM;
}

This is the only 1 that works (comes into the controller method as: {an image of the model - which is what I want, not a string as above):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: { likeOrDislikeVM: holdLikeOrDislikeVM },
     contentType: "application/x-www-form-urlencoded; charset=UTF-8",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 })

enter image description here

Note: I had to create a JavaScript object from the view model defined in this partial view as it seems I could not pass that view model to the controller method. Not sure why. I don' get why I can't use the view model.

Using the view model defined in this partial view to pass to the controller method: Does not work (comes into the controller method as: null):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: { likeOrDislikeVM: '@Model' },
     contentType: "application/x-www-form-urlencoded; charset=UTF-8",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 }) 

Using the view model defined in this partial view to pass to the controller method: Does not work (does not come into the controller, console shows: GbngWebClient is not defined ReferenceError: GbngWebClient is not defined):

 $.ajax({
     type: 'POST',
     url: '@Url.Action("SetModelSessionVar", "BlogPublished")',
     data: { likeOrDislikeVM: @Model},
     contentType: "application/x-www-form-urlencoded; charset=UTF-8",
     error: function (xhr, ajaxOptions, thrownError) {
         alert("Critical Error: something");
     }
 }) 
user3020047
  • 868
  • 1
  • 15
  • 45
  • If you `JSON.stringify` then your action parameter will need to be `public void SetModelSessionVar(string likeOrDislikeVM)` - which it's not, so it doesn't match the parameter, so you get `null` – freedomn-m Sep 07 '20 at 16:33
  • OK. I changed the action method signature. It now works if I change to: contentType: "application/x-www-form-urlencoded; charset=UTF-8", Comes in as: {"BlogId":40,"UserId":3,"LikeCount":0,"DisLikeCount":1,"LikeDisabled":false,"DisLikeDisabled":true}. But with contentType: "application/json", it does not get to the controller. Per this post, the parameter can be defined as the class model and the contentType can be: "application/json". See: https://stackoverflow.com/questions/20226169/how-to-pass-json-post-data-to-web-api-method-as-an-object – user3020047 Sep 07 '20 at 20:36
  • The difference between that answer and yours is that they are passing each parameter at the "root" while you have an extra parameter name: `data: { likeOrDislikeVM: JSON.stringify(holdLikeOrDislikeVM) },` should be `data: JSON.stringify(holdLikeOrDislikeVM),` then the model binder will match the js names to your model names. That post is also confusing because it says you "need to use json.stringify" - you don't, but if you don't then don't use `application/json` - the two go together. it's also an answer for web-api, not mvc which works(worked) slightly differently. – freedomn-m Sep 08 '20 at 07:18
  • freedomn-m, I tried your suggestion and added my findings above. See: Per discussions with freedomn-m, I discovered: – user3020047 Sep 08 '20 at 15:07

0 Answers0