dohmoose
dohmoose

Reputation: 1762

Binding an array of objects in MVC

I am having a problem binding an array of key value pair objects in MVC5. This is the JSON:

{
    "expiration": "2013-12-03T04:30:41.206Z",
    "conditions": [
        {
            "acl": "private"
        },
        {
            "bucket": "ryvus.upload.test"
        },
        {
            "Content-Type": "application/vnd.ms-excel"
        },
        {
            "success_action_status": "200"
        },
        {
            "key": "fc42ae8a-1f6e-4955-a669-8272ad650cb9.csv"
        },
        {
            "x-amz-meta-qqfilename": "simpleupload.csv"
        }
    ]
}

If I attempt to bind conditions to a Dictionary<string, string> like this:

// View Model
public class ResponseVM
{
    public DateTime Expiration { get; set; }
    public Dictionary<string, string> Conditions { get; set; }
}
// Controller Action
public ActionResult MyHandler(ResponseVM s3Response)
{
   //do something
   return JSON(null);
}

I get a 6 entries with keys of "0","1","2","3","4","5" and null values. I seem so close but I've tried a bunch of different types without success, the Dictionary<string, string> was the best I could get.

Am I missing something completely obvious here?

Upvotes: 3

Views: 2917

Answers (3)

Quinton Bernhardt
Quinton Bernhardt

Reputation: 4793

I think the problem lies with the fact that the conditions structure cannot be mapped to a key value pair... the conditions structure is actually an array of objects of different types, where for example the first object can be modelled such:

    public class ACL {
        public string acl { get; set; }
    }

the next object like:

    public class Bucket {
        public string bucket { get; set; }
    }

etc. It's not a bindable key value pair.

To get your conditions structure to bind to a KeyValuePair<TKey, TValue> structure you want your JSON to look more like this:

    {
        "expiration": "2013-12-03T04:30:41.206Z",
        "conditions": [
            {
                Key: "acl",
                Value: "private"
            },
            {
                Key: "bucket",
                Value: "ryvus.upload.test"
            },
            ...
        ]
    }

EDIT: if you cannot change the JSON schema and you are not going to write a custom binder then the following structure should work, .. but it's not pretty because you have and instance of NVPair for each item in conditions.

Your models:

    public class NVPair {
        public string acl { get; set; }
        public string bucket { get; set; }
        [JsonProperty("Content-Type")]
        public string ContentType { get; set; }
        public string success_action_status { get; set; }
        public string key { get; set; }
        ...
    }

    public class ResponseVM
    {
        public DateTime Expiration { get; set; }
        public List<NVPair> Conditions { get; set; }
    }

This way there will be a seperate item for each nvp. But it should bind.

If you don't wanna you JSON.Net's JsonProperty attrib you can use DataContract like here

Upvotes: 0

LostInComputer
LostInComputer

Reputation: 15420

Since the JSON scheme can't be changed, the easiest way is the change the class to match the JSON.

public class ResponseVM
{
    public DateTime Expiration { get; set; }
    public List<Dictionary<string, string>> Conditions { get; set; }
}

Condition is a list of maps.

By the way, the purpose of view models (VM) is for abstracting the view. It's not for input.

Upvotes: 1

Teddy
Teddy

Reputation: 797

$.ajax({
    type: 'POST',
    dataType: 'json',
    data: JSON.stringify(data),
    url: "your url",
    contentType: 'application/json; charset=utf-8',
    success: function (t) {
        // code here
    }
});

Try it.

I didn't bind to dictionary, but array works fine.

Upvotes: 0

Related Questions