Posting an Array of Complex types using JQuery, JSON to ASP.NET MVC

May 26, 2010 · 3 minute read

I recently hit a requirement to take an array of objects and post them to an asp.net mvc action using JQuery’s ajax functionality.

I had to do a bit of Googling to work out how to do this so figured I’d document what I found.

The main two parts to this are getting JQuery to spit out JSON data and ASP.NET MVC to deserialize that data into a strongly typed generic list.

Javascript (JQuery)

$('#saveChanges').click(function () {
    var rules = new Array();
 
    $('#assignedRules table.ruleTable tbody tr').each(function (i) {
        var subRuleCode = $('#subRuleCode', this).val();
        var productGroupId = $('#productGroupId', this).val();
        rules.push(new Rule(subRuleCode, productGroupId));
    });
 
    var postData = JSON.stringify(rules);
 
    $.ajax({
        url: '/rule/SaveUserRules',
        data: postData,
        contentType: 'application/json',
        dataType: 'json',
        type: 'post',
        success: onRulesSaved,
        error: function (data, textStatus) { alert(textStatus); }
    }
    );
});

This javascript

  • creates a new array
  • iterates over some table rows and grabs a couple of hidden field values for each row
  • stores the hidden field values in a javascript class called Rule
  • pushes the Rule instance into the array
  • calls JSON.stringify to construct a valid JSON string from our array of Rules
  • posts the JSON string to our destination URL

As you can see, this script effectively translates a table of values, to an array of Rules which are then sent as JSON to our target URL.

The stringify function uses the script available from here.

The Rule javascript class is simple enough…

function Rule(subRuleCode, productGroupId) {
    this.SubRule = subRuleCode;
    this.ProductGroupId = productGroupId;
}

MVC Action

The next trick is to get the MVC action to accept the array and turn it into a strongly typed generic list.

[AcceptVerbs(HttpVerbs.Post)]
public JsonResult SaveUserRules(List<Rule> usersRules)
{
    // do something here
}

As you can see we simply specify our generic list as the parameter for our action (which accepts HTTP Posts only).

JSON Model Binder

The final piece in the jigsaw is to tell MVC how to bind the JSON data to this generic list of Rules.

I found the code to create a simple JSON model binder here.

public class JsonModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!IsJSONRequest(controllerContext))
        {
            return base.BindModel(controllerContext, bindingContext);
        }
        // get the JSON data that’s been posted
        var request = controllerContext.HttpContext.Request;
        var jsonStringData = new StreamReader(request.InputStream).ReadToEnd();
        return new JavaScriptSerializer()
            .Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
    }
    static bool IsJSONRequest(ControllerContext controllerContext)
    {
        var contentType = controllerContext.HttpContext.Request.ContentType;
        return contentType.Contains(“application/json”);
    }
}

Now all you have to do is register this as the default model binder. Because it inherits the DefaultBinder, and only kicks in if the request type is application/json this shouldn’t break any non-json model binding.

void AddModelBinders()
{
    ModelBinders.Binders.DefaultBinder = new JsonModelBinder();
}

Join the Practical ASP.NET Newsletter

Ship better Blazor apps, faster. One practical tip every Tuesday.

I respect your email privacy. Unsubscribe with one click.