views:

142

answers:

2

When using DataContractJsonSerializer to serialize a dictionary, like so:

[CollectionDataContract]
public class Clazz : Dictionary<String,String> {}

    ....

    var c1 = new Clazz();
    c1["Red"] = "Rosso";
    c1["Blue"] = "Blu";
    c1["Green"] = "Verde";

Serializing c1 with this code:

    var dcjs = new DataContractJsonSerializer(c1.GetType());
    var json = new Func<String>(() =>
        {
            using (var ms = new System.IO.MemoryStream())
            {
                    dcjs.WriteObject(ms, c1);
                    return Encoding.ASCII.GetString(ms.ToArray());
            }
        })();

...produces this JSON:

[{"Key":"Red","Value":"Rosso"},
 {"Key":"Blue","Value":"Blu"},
 {"Key":"Green","Value":"Verde"}]

But, this isn't a Javascript associative array. If I do the corresponding thing in javascript: produce a dictionary and then serialize it, like so:

var a = {};
a["Red"] = "Rosso";
a["Blue"] = "Blu";
a["Green"] = "Verde";

// use utility class from http://www.JSON.org/json2.js
var json = JSON.stringify(a);

The result is:

{"Red":"Rosso","Blue":"Blu","Green":"Verde"}

How can I get DCJS to produce or consume a serialized string for a dictionary, that is compatible with JSON2.js ?


I know about JavaScriptSerializer from ASP.NET. Not sure if it's very WCF friendly. Does it respect DataMember, DataContract attributes?

+1  A: 

I raised a bug on MS Connect for the behavior I described above.

Please vote it up.

Cheeso
A: 

What it is doing is perfectly sensible, the JSON it produces is a reasonable representation of a .net dictionary in JSON. If you wanted the JSON output you describe you would need to serialise a class like

public class ColourThingy
{
      public string Red {get;set;}
      public string Blue {get;set;}
      public string Green {get;set;}
}
ColourThingy MyColourThingy = new ColourThingy();
MyColourThingy.Red = "Rosso";
...

Remember JavaScript associative arrays are not really arrays, you are simply exploiting the fact that object["key"] is another way of refering to object.key. As such when it serialises a .net dictionary to JSON it produces an array of key/value pair objects, exactly as you would expect.

Ben Robinson
I know that JavaScript assoc arrays are not arrays. They are *dictionaries*. I'd expect DataContractJsonSerializer to be able to de-serialize into a .NET Dictionary, using the form that JSON2.js produces. And vice-versa. I know that the JSON produced by DCJS is a faithful representation of the dictionary content. I dispute that it is "reasonable" since it cannot be de-serialized into a dictionary by JSON.js . A 4-line js function would correct that, but. . . it would be nice for DCJS to just do the right (interoperable) thing, in the first place.
Cheeso
The thing is JS assoc arrays are not dictionaries, they are just objects. It is simply a feature of the language that you can refer to object properties in a dictionary/associative array type syntax, e.g. object["property"] as well as object.property. If you were to serialise .net dictionarys in the way that you describe it would require special casing the dictionary object and doing it differently to every other object, this would mean that if you created your own class that was identitcal to a dictionary it would serialise one way but if you used a real dict it would do it another way
Ben Robinson
Depending on your point of view, a JS object is, or is not, a dictionary. The question is, will the JSON serialization framework in .NET require a pre-defined type for every JS object, or not? I can see both sides, but I favor the more flexible approach when dealing with JS because *There is no way to define a fixed type* in JS. Every object can be extended, every list of properties is dynamic. Therefore it is unnatural and artificial to require a formal .NET type to interface with dynamic JS objects. A Dictionary makes sense. (I haven't considered the new .NET 4.0 dynamic type in all this.)
Cheeso
I think you sort of make my point for me "will the JSON serialization framework in .NET require a pre-defined type for every JS object" the answer is no, it follows a general pattern and creates JSON formatted JS objects as close as possible to the the .Net object. A .Net dictionary has a keys property that is a collection and a values property that is a collection and serialising it produces a JS ovject with a keys propery that is an array and a values property that is an array.
Ben Robinson