Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble model binding a JSON array to a List in ASP.NET MVC 3

I am having trouble model binding a JSON array to a C# list in MVC 3.

I have an object called a DockState. It looks like this:

[Serializable]
public class DockState
{
    public bool Closed { get; set; }
    public bool Collapsed { get; set; }
    public string DockZoneID { get; set; }
    public int ExpandedHeight { get; set; }
    public Unit Height { get; set; }
    public int Index { get; set; }
    public Unit Left { get; set; }
    public bool Pinned { get; set; }
    public bool Resizable { get; set; }
    public string Tag { get; set; }
    public string Text { get; set; }
    public string Title { get; set; }
    public Unit Top { get; set; }
    public string UniqueName { get; set; }
    public Unit Width { get; set; }
}

My action method accepts a list of dock states, like this:

public JsonResult SaveDockStates(List<DockState> dockStates)

On the client I am building an array of JSON objects that contain all the same properties as the C# DockState object. I am then assigning this array to a JSON object of its own with the property of the argument in the action method, like this:

function get_allDockStates()
{
    var allRadDocks = []; // declare array.
    var allRadControls = $telerik.radControls; // use telerik API to obtain all controls.

    // loop through all telerik controls.
    for (var i = 0; i < allRadControls.length; i++)
    {
        var element = allRadControls[i];

        // Check if control is a rad dock element.
        if (Telerik.Web.UI.RadDock && element instanceof Telerik.Web.UI.RadDock)
        {
            // Build a JSON object containing the same properties as the C# DockState
            // object. Leaving out a couple that should just be null anyway. Add new
            // JSON object to array.
            Array.add(allRadDocks,
            {
                UniqueName: element._uniqueName,
                DockZoneID: element._dockZoneID,
                Width: element._width,
                Height: element._height,
                ExpandedHeight: element._expandedHeight,
                Top: element._top,
                Left: element._left,
                Resizable: element._resizable,
                Closed: element._closed,
                Collapsed: element._collapsed,
                Pinned: element._pinned,
                Title: element._title,
                Index: element._index
            });
        }
    }
    // Return the array.
    return allRadDocks;
}

// This function is fired by the rad dock controls when they are moved.
function positionChanged(sender, e)
{
    // obtain the array of dock states.
    var dockStates = get_allDockStates();
    // Make ajax call to MVC action method to save dock states.
    jQuery.ajax({
        data: { dockStates: dockStates },
        type: 'POST',
        dataType: 'json',
        url: '/AjaxServices/DashboardService/SaveDockStates'
    });
}

Unfortunately something rather odd happens when the AJAX call is made. It hits the action method and my List<DockState> does have items in it.

http://www.codetunnel.com/content/images/dockStateListInstantiated.jpg

However, the items in the list are all default. Meaning all their values are the default values, not the ones submitted in the request.

http://www.codetunnel.com/content/images/dockStatesDefaultValues.jpg

I'm not sure why the list contains the correct number of items, but all items appear to be nothing more than instantiated. Their properties were not set to the values in the JSON array. The request definitely contains the right data, as shown here:

http://www.codetunnel.com/content/images/dockStatesFormData.jpg

Am I doing something wrong? Is the form data formatted incorrectly? Is there a problem with the default model binder?

Update (testing Darin Dimitrov's answer)

I discovered that JSON was being overridden by an unused old script. I have removed and now JSON.stringify is working fine. Here is the request payload.

http://www.codetunnel.com/content/images/dockStatesJsonStringify.jpg

Much better. However now when I am debugging my list has zero items in it. This did not seem to fix the problem, though I appreciate the effort :)

like image 778
Chev Avatar asked Dec 10 '22 06:12

Chev


1 Answers

Try sending a JSON request:

jQuery.ajax({
    // TODO: Never hardcode urls like this => always use URL helpers
    // when you want to generate an url in an ASP.NET MVC application
    url: '/AjaxServices/DashboardService/SaveDockStates',
    type: 'POST',
    data: JSON.stringify({ dockStates: dockStates }),
    contentType: 'application/json; charset=utf-8',
    success: function(result) {
        // TODO: process the results
    }
});

The JSON.stringify method is natively built into modern browsers. If you want to support legacy browsers you need to include the json2.js script to your page.

like image 142
Darin Dimitrov Avatar answered Dec 11 '22 20:12

Darin Dimitrov