You can't. Well you can. But out of the box you can't. This is due to the fact that the Dictionary could be using any type as the key. In JSON, it can only either be an int or string. So in some cases the CLR Dictionary<K,V> object doesn't map directly to the JsonObject.
A simple 'hack' to get around this is described here. This is all fine and dandy if you are only serializing that single Dictionary. But when it's nested within custom types ....
Which is why I wonder the usefulness of this method since you could just use the JavaScriptSerializer instead of the DataContractJsonSerializer, which serializes and deserializes dictionaries nicely.
For me, the final solution is to use the IDataContractSurrogate interface. The following is the surrogate class used. Basically, if the DataContractJsonSerializer comes across a Dictionary<string,string>, it will use the Javascript serializser instead. You could probably modify it for handling Dictionary<string,object> as well.
public class JsonSurrogate : IDataContractSurrogate
{
[DataContract]
public class SDictionary
{
[DataMember] public string data;
}
public Type GetDataContractType(Type type)
{
if (type == typeof(Dictionary<string, string>))
{
return typeof (SDictionary);
}
return type;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is Dictionary<string, string>)
{
SDictionary jd = new SDictionary();
JavaScriptSerializer js = new JavaScriptSerializer();
jd.data = js.Serialize(obj);
return jd;
}
return obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is SDictionary)
{
SDictionary jd = (SDictionary)obj;
JavaScriptSerializer js = new JavaScriptSerializer();
return js.Deserialize<Dictionary<string, string>>(jd.data);
}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, bject customData)
{
if (typeNamespace.Equals("http://schemas.datacontract.org/2004/07/DCSurrogateSample"))
{
if (typeName.Equals("SDictionary"))
{
return typeof(Dictionary<string, string>);
}
}
return null;
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
}
To use the above, use the following constructor when creating your DataContractJsonSerializer.
DataContractJsonSerializer ser = new DataContractJsonSerializer(poco.GetType(), new[]{typeof(JsonSurrogate.SDictionary)}, int.MaxValue, false, new JsonSurrogate(), false);