Q:

Pass multiple JSON objects to MVC3 action method

JQuery code:

    //This passes NULL for "CategoryID", "CategoryName", "ProductID", "ProductName"
     $("#btnPost").click(function () {
            var CategoryModel = {
                CategoryID: 1,
                CategoryName: "Beverage"
            };
            var ProductModel = {
                ProductID: 1,
                ProductName: "Chai"
            };
            var data1 = {};

            data1["cat"] = CategoryModel;
            data1["prd"] = ProductModel;

            var jsonData = JSON.stringify(data1);

            $.ajax({
                url: url + '/Complex/ModelTwo', //This works but property values are null 
                type: 'post',
                dataType: 'json',           
                data: { "cat": CategoryModel, "prd": ProductModel }, //jsonData,
                cache: false,
                success: function (result) {
                    alert(result);
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert(thrownError);
                }
            });
        });

MVC Code (C#):
     public class ComplexController : Controller
    {
        public string ModelOne(Category cat)
        {
            return "this took single model...";
        }

        public string ModelTwo(Category cat, Product prd)
        {
            return "this took multiple model...";
        }
    }
    public class Category
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
    }
    public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
    }

Now the issue is, I couldn't get it working by passing "CategoryMode", "ProductModel" into "ModelTwo" action method. The JQuery post correctly identifies the action method "ModelTwo" but "cat", "prd" property values are null. "CategoryID", "CategoryName", "ProductID", "ProductName" all are null despite hitting that method. 

    //THIS ONE WORKS FINE...

     $("#btnPost").click(function () {
            var CategoryModel = {
                CategoryID: 1,
                CategoryName: "Beverage"
            };
            var ProductModel = {
                ProductID: 1,
                ProductName: "Chai"
            };
            var data1 = {};

            data1["cat"] = CategoryModel;
            data1["prd"] = ProductModel;

            var jsonData = JSON.stringify(data1);

            $.ajax({
                url: url + '/Complex/ModelOne', //This works
                type: 'post',
                dataType: 'json',           
                data: CategoryModel,
                cache: false,
                success: function (result) {
                    alert(result);
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert(thrownError);
                }
            });
        });

So what's wrong with my first JQuery call to "ModelTwo" action method?
I spent lots of time figuring this out, but not sure what's going on. There is no issue with routing here because I can land on the right action method...
Any help will be greatly appreciated.
Thanks!

A:

You could send them as JSON request:
var categoryModel = {
    categoryID: 1,
    categoryName: "Beverage"
};
var productModel = {
    productID: 1,
    productName: "Chai"
};
$.ajax({
    url: '@Url.Action("ModelTwo")',
    type: 'post',
    dataType: 'json',
    // It is important to set the content type
    // request header to application/json because
    // that's how the client will send the request
    contentType: 'application/json',
    data: JSON.stringify({ cat: categoryModel, prd: productModel }),
    cache: false,
    success: function (result) {
        alert(result);
    },
    error: function (xhr, ajaxOptions, thrownError) {
        alert(thrownError);
    }
});

The JSON.stringify method that I am using in my example is natively built-in all modern browsers but if you need to support legacy browsers you could include the json2.js script to your page.
This should correctly bind to the following action:
[HttpPost]
public ActionResult ModelTwo(Category cat, Product prd)
{
    return Json(new { message = "this took multiple model..." });
}

But I would recommend you defining a view model:
public class MyViewModel
{
    public Category Cat { get; set; }
    public Product Prd { get; set; }
}

and then have your controller action take this view model:
[HttpPost]
public ActionResult ModelTwo(MyViewModel model)
{
    return Json(new { message = "this took a single view model containing multiple models ..." });
}

and of course the client side code stays the same.

