开发者

Simulating a form POST to ASP.NET MVC with javascript

I've had problems trying to send JSON to ASP.NET MVC Controllers. I don't want to accept one string parameter on each controller method and deserialize manually. I have found that constructing a collection of post variables works reliably, but I don't have a generalized function to do so. I can write one myself if no one has done it already but I find it really hard to believe.

If no one answers this by tomorrow I guess I'll stop being lazy.

Edit: To be clear, I'm not asking how to serialize .NET objects to JSON. I'm asking if anyone has written a javascript function to do the following:

given javascript object:

{ 
    name: { first: "first", last: "last" }, 
    age: 35,
    drinks: [
        { carbonated: false, name: "juice" },
        { carbonated: true, name: "soda" }
    ]
}

returns (POST request as object):

name.first  :   first
name.last   :   last
age         :   35
drinks[0].carbonated 开发者_如何学JAVA   :   false
drinks[0].name          :   juice
drinks[1].carbonated    :   true
drinks[1].name          :   soda

Thanks.


It depends on how deep you want the serialization to work. You can use the $.param(obj) method in jQuery to do simple object serialization, but it won't work on your example as it assumes that the values are simple types or arrays of simple types. You might want to look at the code for param and adapt it to your specialized needs. Essentially, you'd need to determine when the value is an object and use that to append the keys in the object to the outer key when constructing the key/value arrays. Handling arrays of complex objects would take some similar fiddling to get the key indices set up correctly.

The following has been tested in FF3.5/IE8. No guarantees for other browsers but I think it ought to work.

jQuery.extend( {
    isObject: function(obj) {
       return typeof(obj) === "object";
    },
    complexParam: function( a ) {
        var s = [ ];

        function add( key, value ){
            s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
        };

        // If an array was passed in, assume that it is an array
        // of form elements
        if ( jQuery.isArray(a) || a.jquery )
            // Serialize the form elements
            jQuery.each( a, function(){
                add( this.name, this.value );
            });

        // Otherwise, assume that it's an object of key/value pairs
        else
            // Serialize the key/values
            for ( var j in a )
                // If the value is an array then the key names need to be repeated
                if ( jQuery.isArray(a[j]) )
                    jQuery.each( a[j], function(){
                        if (jQuery.isObject(this)) {
                            var idx = 0;
                            for (var k in this) {
                               add( j + "[" + idx + "]." + k, this[k] );
                               ++idx;
                            }
                        }
                        else {
                             add( j, this );
                        }
                    });
                else {
                    if (jQuery.isFunction(a[j])) {
                       add( j, a[j]() );
                    }
                    else if (jQuery.isObject(a[j])) {
                       for (var k in a[j]) {
                          add( j + "." + k, a[j][k] );
                       }
                    }
                    else {
                        add( j, a[j] );
                    }
                }

        // Return the resulting serialization
        return s.join("&").replace(/%20/g, "+");
    }
});

Called as

var serialized = $.complexParam( obj );

Note that this leaves the brackets URL-encoded. If that isn't ok, then add

.replace(/%5B/g, "[").replace(/%5D/g, "]")

to the return in complexParam()


Maybe this will help:

http://aleembawany.com/2009/05/22/json-serializers-in-net/

C# automatic property deserialization of JSON


So, there's the System.Runtime.Serialization.Json.DataContractJsonSerializer class in .Net v3.5 and up. It serializes and deserializes JSON data to objects. You'll have to reference System.ServiceModel.Web assembly.

The System.Web.Mvc.Controller.Json() function can handle your serialization needs too.

So you've got the controller covered there and it sounds like you've got the javascript side covered, right?


Their a question already where someone has written a Action filter to do this, you might want to check out their solution.

Binding application/json to POCO object in asp.net mvc, Serialization exception


I don't know if this is the sort of answer you actually want to hear, but I personally wouldn't try to push absolutely everything to a JSON object in javascript where you still need to do a fair bit of work on the other end.

The way I do this currently is by passing through the Request.Form value from the Controller to the model base object, which then uses reflection to pull the necessary values from the Request.Form variable and update the values in the model object. So basically you can use a single method call to save all core details of an object without worrying about pulling the form apart manually. An example of this would be:

Job temp = new Job();
temp.UpdateDetails(Request.Form);

This would generally be in your 'Save' or equivalent action, and will obviously work with existing objects in the same way. Please note that this is a single method on your base class, you do not need to re-implement this on each of your model objects. Using this method should greatly cut down the complexity/size of your code (both your javascript and back end code) in comparison with individually serialising JSON objects.

I can go into more detail explaining this method if you would like, but I won't go to the extra effort of explaining each individual step if this is not what you require as I realise this isn't what your original question is about.


I use jQuery's $.toJSON to serialize the object in the javascript side, and then deserialize it the controller side using Json.Net (I found that the stock JSON deserializing in ASP.NET MVC barfs at times on some inputs).


This is a Mootools version of what I wanted. I was actually unaware that the Mootools Hash.toQueryString() almost does this by default. It formats arrays in a way that ASP.NET MVC won't recognize so I still needed to implement my own:

var POSTEncoder = {
getHash: function(request, prefix, out) {

    if($type(out) != 'object') { out = {}; }

    function add(key, value){
        out[ key ] = value;
    };

    var validPrefix = $type(prefix) == 'string';

    switch($type(request)) {
        case 'array':

            if(!validPrefix) { prefix = 'request'; }

            request.each(function(item, i){
                POSTEncoder.getHash(item, prefix + '[' + i + ']', out);
            });

            break;

        case 'object':

            if(!validPrefix) { prefix = ''; }

            new Hash(request).each(function(val, key) {
                POSTEncoder.getHash(val, (prefix != '' ? prefix + '.' : '') + key, out);
            });

            break;

        case 'string':
        case 'number':
        case 'boolean':
        case 'date':

            if(!validPrefix) { prefix = 'request'; }

            add(prefix, request);

            break;
        case false:
            add(prefix || 'request', '');
    }

    return new Hash(out);
}};

POSTEncoder.getHash(request) will flatten out the request into key/value pairs suitable for a form POST. POSTencoder.getHash(request).toQueryString() will turn that into a query string.

Example:

var test = {
bool: true,
strng: 'a',
numbr: 1,
basicArr: ['d','e','f'],
basicObj: {x:1, y: 'z'},
objectArr: [{n:1, o:2}, {n:3,o:4}],
complex: {
    one: 1,
    two: 'two',
    three: [{x:1},{x:2},{x:3}]
}};

var hash = POSTEncoder.getHash(test);

console.log(hash);
console.log(hash.toQueryString());
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜