75

I have been trying the whole afternoon crawling through the web trying to receive a JSON object in the action controller.

What is the correct and or easier way to go about doing it?

I have tried the following: 1:

//Post/ Roles/AddUser
[HttpPost]
public ActionResult AddUser(String model)
{
    if(model != null)
    {
        return Json("Success");
    }else
    {
        return Json("An Error Has occoured");
    }

}

Which gave me a null value on my input.

2:

//Post/ Roles/AddUser
[HttpPost]
public ActionResult AddUser(IDictionary<string, object> model)
{
    if(model != null)
    {
        return Json("Success");
    }else
    {
        return Json("An Error Has occoured");
    }

}

which gives me a 500 error on the jquery side which is trying to post to it? (meaning that it didn't bind correctly).

here is my jQuery code:

<script>
function submitForm() {

    var usersRoles = new Array;
    jQuery("#dualSelectRoles2 option").each(function () {
        usersRoles.push(jQuery(this).val());
    });
    console.log(usersRoles);

    jQuery.ajax({
        type: "POST",
        url: "@Url.Action("AddUser")",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: JSON.stringify(usersRoles),
        success: function (data) { alert(data); },
        failure: function (errMsg) {
            alert(errMsg);
        }
    });
}

All I want to do is receive my JSON object in my mvc action?

Patrick
  • 674
  • 1
  • 8
  • 22
Zapnologica
  • 22,170
  • 44
  • 158
  • 253
  • While this specifies MVC5, the solution is the same, so this is a duplicate of [Posting JSON Data to ASP.NET MVC](http://stackoverflow.com/questions/4164114/posting-json-data-to-asp-net-mvc) – Chris Moschini Apr 05 '16 at 22:15

4 Answers4

89

Unfortunately, Dictionary has problems with Model Binding in MVC. Read the full story here. Instead, create a custom model binder to get the Dictionary as a parameter for the controller action.

To solve your requirement, here is the working solution -

First create your ViewModels in following way. PersonModel can have list of RoleModels.

public class PersonModel
{
    public List<RoleModel> Roles { get; set; }
    public string Name { get; set; }
}

public class RoleModel
{
    public string RoleName { get; set;}
    public string Description { get; set;}
}

Then have a index action which will be serving basic index view -

public ActionResult Index()
{
    return View();
}

Index view will be having following JQuery AJAX POST operation -

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script>
    $(function () {
        $('#click1').click(function (e) {

            var jsonObject = {
                "Name" : "Rami",
                "Roles": [{ "RoleName": "Admin", "Description" : "Admin Role"}, { "RoleName": "User", "Description" : "User Role"}]
            };

            $.ajax({
                url: "@Url.Action("AddUser")",
                type: "POST",
                data: JSON.stringify(jsonObject),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                error: function (response) {
                    alert(response.responseText);
            },
                success: function (response) {
                    alert(response);
                }
            });

        });
    });
</script>

<input type="button" value="click1" id="click1" />

Index action posts to AddUser action -

[HttpPost]
public ActionResult AddUser(PersonModel model)
{
    if (model != null)
    {
        return Json("Success");
    }
    else
    {
        return Json("An Error Has occoured");
    }
}

So now when the post happens you can get all the posted data in the model parameter of action.

Update:

For asp.net core, to get JSON data as your action parameter you should add the [FromBody] attribute before your param name in your controller action. Note: if you're using ASP.NET Core 2.1, you can also use the [ApiController] attribute to automatically infer the [FromBody] binding source for your complex action method parameters. (Doc)

enter image description here

Patrick
  • 674
  • 1
  • 8
  • 22
ramiramilu
  • 17,044
  • 6
  • 49
  • 66
  • 1
    Ah, so it needs to be a POST? I had the same problem, the argument of the model being `null`, but when I added POST to my ajax call and to the mvc controller, my model isn't null anymore. Only thing bothering me is that if you assign and empty string to one of the properties in javascript, and pass this object with ajax to the server, in C# the server reads these empty string properties as `null`. I'd rather like them to be an empty string in C# too. – QuantumHive Mar 11 '15 at 10:23
  • found the solution to the problem described above: http://stackoverflow.com/questions/12734083/string-empty-converted-to-null-when-passing-json-object-to-mvc-controller – QuantumHive Mar 11 '15 at 10:26
  • 2
    I copy/pasted this and I 'hit' the method but the model.Name is null (as are the Roles) I am using .NET Core - is there a setting I have to change? – Rune Jeppesen Sep 01 '16 at 09:20
  • 2
    @RuneJeppesen I know, it's late, but for everyone else wondering how to get it work in ASP.NET Core, simply add `[FromBody]` to your Model parameter: `public ActionResult AddUser([FromBody] PersonModel model)`. – jAC Aug 29 '17 at 09:29
  • can you tell me what change will be required if in your example instead of POST I want to use a GET in the ajax call. – user734028 May 05 '18 at 07:16
  • I was having trouble getting it to bind. Turns out I had forgotten to make my class members public. – kmxr Sep 05 '19 at 19:14
15

There are a couple issues here. First, you need to make sure to bind your JSON object back to the model in the controller. This is done by changing

data: JSON.stringify(usersRoles),

to

data: { model: JSON.stringify(usersRoles) },

Secondly, you aren't binding types correctly with your jquery call. If you remove

contentType: "application/json; charset=utf-8",

it will inherently bind back to a string.

All together, use the first ActionResult method and the following jquery ajax call:

    jQuery.ajax({
        type: "POST",
        url: "@Url.Action("AddUser")",
        dataType: "json",
        data: { model: JSON.stringify(usersRoles) },
        success: function (data) { alert(data); },
        failure: function (errMsg) {
        alert(errMsg);
        }
   });
Mike Lorenzana
  • 506
  • 4
  • 20
  • 1
    This worked for me, I got rid of the stringify as it put quotes around my string but when I didn't call stringify it came in without the quotes to the controller. This allowed me to get a string into my controller with a post. This gets my upvote. – Steven Edison May 03 '16 at 18:18
4

You are sending a array of string

var usersRoles = [];
jQuery("#dualSelectRoles2 option").each(function () {
    usersRoles.push(jQuery(this).val());
});   

So change model type accordingly

 public ActionResult AddUser(List<string> model)
 {
 }
Murali Murugesan
  • 22,423
  • 17
  • 73
  • 120
3

fwiw, this didn't work for me until I had this in the ajax call:

contentType: "application/json; charset=utf-8",

using Asp.Net MVC 4.

Sid
  • 14,176
  • 7
  • 40
  • 48
Trober
  • 259
  • 1
  • 2
  • 8