1

How can I pass the following back to an mmvc3 controller ActionResult?

var hashtable = {};
hashtable['screaming'] = ["1", "2"];
hashtable['mellow'] = ["3", "4", "5"];
$.get('@Url.Action("PerformMagic")', { 'theValues': hashtable }, function (data) {
    //Callback..    
});

What would my controller method sig look like?

public ActionResult PerformMagic(/*What type goes here? string[] theValues or string[][] theValues)
{
}

2 Answers 2

3

If you want to pass the hashtable value to an action the most natural way would be to pass it as a dictionary to an action

public ActionResult PerformMagic(Dictionary<String, List<int>> theValues)
{
    // the magic!
}

When passing the values using jQuery Ajax functionality to the ASP.NET MVC action you're facing a big framework misunderstanding. The ASP.NET MVC ModelBinder expects values that should be bound to a Dictionary in the request body or URL using this naming scheme

theValues[0].key=key0
theValues[0].value[0]=values0.0
theValues[0].value[1]=values0.1
theValues[1].key=key1
theValues[1].value[0]=values1.0
theValues[1].value[1]=values1.1
theValues[1].value[2]=values1.2

This blog post gives further detail about the ASP.NET MVC naming scheme for dictionaries and lists.

But jQuery uses this naming scheme to pass values in the request body or URL

theValues[key0][]=value0.0
theValues[key0][]=value0.1
theValues[key1][]=value1.0
theValues[key1][]=value1.1
theValues[key1][]=value1.2

In both examples I omitted the '&' and split the request values in separate lines for better readability.

So if you want to pass the values as a Dictionary to the action method you need to make jQuery and ASP.NET MVC Model Binders talk. I can think of two options:

  1. Change the naming scheme that ASP.NET MVC expects for request parameters
  2. Change the naming scheme that jQuery uses to build request parameters

Method 1 would require you to write your own Model Binder and since the naming functionality for binding to Dictionary action arguments is somewhere hidden in an internal UpdateDictionary method, writing your own Model Binder would imply to copy a lot of ASP.NET MVC DefaultModelBinder code...

Method 2 should be fairly simple to implement because jQuery uses the param function to build request parameters and the jQuery ajax function allows you to just pass in raw values that were transformed by a custom function to request parameters. More detail about jQuery ajax function can be found here. See section 'processData'.

I'll give a prototype jQuery implementation to pass the hashtable var as a dictionary parameter to an ASP.NET MVC controller action:

function buildParams(prefix, dict) {
    var s = [],
    add = function (key, value) {
        // If value is a function, invoke it and return its value
        value = jQuery.isFunction(value) ? value() : value;
        s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
    };

    var i = 0;

    jQuery.each(dict, function (key, values) {
        add(prefix + '[' + i + '].key', key);

        jQuery.each(values, function (j, value) {
            add(prefix + '[' + i + '].value[' + j + ']', value);
        });

        i++;
    });

    return s.join('&');
}

$(function () {
    $('#submithashes').click(function (e) {
        var hashtable2 = {};
        hashtable2['screaming'] = ["1", "2"];
        hashtable2['mellow'] = ["3", "4", "5"];

        $.ajax({
            type: "POST",
            url: '@Url.Action("PerformMagic")',
            dataType: 'json',
            processData: false,
            data: buildParams('theValues', hashtable2),
            success: function () {

            }
        });

        e.preventDefault();
    });
});

The interesting parts in this prototype implementation are that it uses POST, it's using jQuery ajax not the $.get or $.post shortcuts because the shortcuts don't expose the possibility to specify processData: false and that request params are build using the custom buildParams function and not via $.param jQuery function.

Sign up to request clarification or add additional context in comments.

Comments

1

What do you want your controller to look like? You could break it up like this:

public ActionResult PerformMagic(string[] screaming, string[] mellow) { }

$.get('@Url.Action("PerformMagic")', { screaming: hashtable.screaming, mellow: hashtable.mellow }

Or if you want to pass a string[][], this might work

var hashtable = [];
hashtable.push(["1", "2"]);
hashtable.push(["3", "4", "5"]);

$.get('@Url.Action("PerformMagic")', { arrayOfArrays: hashtable }

2 Comments

Yes, I'm definitely leaning towards passing in the entire hashtable as opposed to passing in separate arrays[]. I guess I could try to see if PerformMagic(string[][] theValues) works.
@JaJ - I think MVC would be smart enough to handle that. Just make sure you change the definition of hashtable to [] instead of {} (as above in the second example)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.