0

I have the following JavaScript object:

var parameters = { "parameters" :
    [
        {
            "key": "feedbackSource",
            "value": "foo"
        }, {
            "key": "status",
            "value": "foo"
        }, {
            "key": "feedbackType",
            "value": "foo"
        }
    ]
};

console.log(JSON.stringify(parameters)) shows:

{"parameters":[{"key":"feedbackSource","value":"foo"},{"key":"status","value":"foo"},{"key":"feedbackType","value":"foo"}]}

AJAX:

$.ajax({
    type: "POST",
    url: "myPage.aspx/MyMethod",
    data: JSON.stringify(parameters),
    contentType: "application/json; charset=utf-8",
    dataType: "json"
});

Method:

[WebMethod]
public static void MyMethod(object parameters)
{

}

Question: How do I iterate over that object in C# to get the contents?

I have tried:

foreach (var p in (IEnumerable) parameters)
{
    foreach (var x in (IEnumerable) p)
    {
        var test = x;
    }
}

But test on the first iteration is a Key Value pair, with Key = "key" and Value = "feedbackSource". On the second iteration, Key = "value" and Value = "foo"

And that doesn't seem like the correct way to iterate over the object. I would expect the Key = "feedbackSource" and Value = "foo".

devlin carnate
  • 8,309
  • 7
  • 48
  • 82

2 Answers2

1
var parameters =
            {
                "parameters":
                [
                    {"feedbackSource": "foo", "status": "foo", "feedbackType": "foo"}
                ]
            };

create below class

public class mComputedProp
{
    public string feedbackSource { get; set; }
    public string status { get; set; }
    public string feedbackType { get; set; }
}

public class mcomputedprops
    {
        [JsonProperty("parameters")]
        public List<mComputedProp> mprops = new List<mComputedProp>();
    }

Modify your ajax call

$.ajax({
                type: "POST",
                url: '@Url.Action("getComputedProperty", "Home")',
                contentType: "application/json; charset=utf-8",
                async: false,
                dataType: "json",
                data: JSON.stringify({ listjson: JSON.stringify(parameters) })                    
            });


[WebMethod]
    public void getComputedProperty(string listjson)
        {
            mcomputedprops mod = JsonConvert.DeserializeObject<mcomputedprops>(listjson);
            string asdf = mod.mprops[0].feedbackSource.ToString();
        }
Nagaraj Raveendran
  • 1,150
  • 15
  • 23
1

"How do I iterate over that object in C# to get the contents"

After a good discussion with @Devlin about this - the following conclusion has been reached:

Current JSON data structure

The JSON string that is being generated (from the page) is a little confusing to say the least.

The existing data structure of

{ "parameters" : [ { "key": "feedbackSource", "value": "foo" }, { "key": "status", "value": "foo" }, { "key": "feedbackType", "value": "foo" } ] };

Was very confusing and obfuscated the data somewhat - making it very hard to traverse and iterate the objects inside.

It appeared to be of key:(key/value) pairs/pairs (wait, what?)

I proposed to structure a proper key/value pair structure to the JSON firstly (from within the page).

Like so:

{ "parameters" : 
    [ 
        { 
            "feedbackSource" : "foo" 
        }, 
        { 
            "status" : "foo" 
        }, 
        { 
            "feedbackType" : "foo" 
        } 
    ] 
} 

What is the ModelBinder doing?

As per @Devlin's screenshot: debug screenshot

The ModelBinder was cleverly assiging parameter as a Dictionary<string, object>, because it recognised the JSON as key/value pairs - in which the values were yet again key value pairs.

Obviously, every type in C# derives from object, so accepting this was just boxing it in an object.

Thus why other suggestions of casting to a string weren't successful.

ASP.NET has a ModelBinder which is able to detect types of objects passed to methods, to make it easier when getting data out in the method.


Passing in/using the right type

Suggestion 1

Cast the object parameter in the MyMethod signature to a Dictionary<string, string> (do it safely, where possible)

Like so:

var paramsDict = parameters as Dictionary<string, object>;
if (paramsDict != null)
{
    // Iterate over the dictionary in here
}

Suggestion 2

Seeing as we know that the object parameters is already of type Dictionary<string, object> (thanks to some wizardry by the ModelBinder), we could just use this type in the MyMethod signature, instead.

Like this:

[WebMethod]
public static void MyMethod(Dictionary<string, object> parameters)
{
    // Iterate in here
}

Iterating the data

Now that you've got a nice and easy to use Dictionary<string, object>, it is simple to iterate over it and grab the values from there.

Like this:

foreach (var param in paramsDict) // or "... in parameters" if you're using suggestion 2
{
    var key = param.Key;
    var value = param.Value;

    // Manipulate/persist the data
}

It's up to you how you then manipulate/persist the data, but this should give you a starting point of getting the data from your JSON object.

Summary

  • Change your JSON structure to be "proper" key/value pairs
  • Default ModelBinder is able to assign the JSON as a C# Dictionary<string, object>
  • Either change the MyMethod signature to accept Dictionary<string, object> type for parameter, or cast the parameter object to a Dictionary (both should work the same)
  • Iterate each item in the Dictionary. You can then access the Keys and Values of each item, and then manipulate the data however you wish

Furthermore
Given that your JSON string is passing in key/value pairs of string and string, I suspect that you may safely use Dictionary<string, string> to be picked up by the ModelBinder, or when casting etc. confirmation may be needed on this, however

Hope this helps, and best of luck in your project! :)

Geoff James
  • 3,122
  • 1
  • 17
  • 36
  • `if (paramsString != null)` is false. In other words, paramString is null. Why? – devlin carnate Jul 15 '16 at 21:04
  • It's a safe casting check, if the `parameters` `object` is not (for some reason) a string. Casting using `parameters as string` will not throw an exception (like the `(string)parameters` cast), and instead will create a `null` `string` - hence the `null` check. – Geoff James Jul 15 '16 at 21:05
  • When I cast parameters to string, it is null. Here's what I see in debug: http://imgur.com/0NUtqzf – devlin carnate Jul 15 '16 at 21:17
  • Then that would explain why when you change the method signature to `string parameters` the binding is not working correctly - by the looks of it, your binder *may have* actually realised that it's already of type `IEnumerable>` – Geoff James Jul 15 '16 at 21:19
  • If the above is true, then you could simply cast the `parameters` to that type, and iterate over it in a similar way as above: `foreach (var param in paramsKVPs) { key = param.Key; value = param.Value; ... }` – Geoff James Jul 15 '16 at 21:22
  • casting to `IEnumerable>` yields null as well. – devlin carnate Jul 15 '16 at 21:28
  • I would suggest seeing what type it is first, then. Just create a Type object and inspect it in your debugger: `Type parametersType = parameters.GetType();` – Geoff James Jul 15 '16 at 21:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/117461/discussion-between-geoff-james-and-devlin-carnate). – Geoff James Jul 15 '16 at 21:42