When you deserialize to Dictionary<string, object> Json.Net does not have any type information that will be used to determine what needs to be created for the dictionary values. The usual solution is to either use a strongly typed container (for example, Dictionary<string, Rect> ), or set the TypeNameHandling option to Objects in the serializer. The latter will inform Json.Net of the release of type metadata with JSON so that when deserializing it knows what type needs to be created.
However, some types, such as System.Windows.Rect , are marked with the [TypeConverter] attribute. When Json.Net finds this type, it uses the associated TypeConverter to serialize the object into a string, rather than treat it like a regular object. Unfortunately, when this conversion occurs, the original type information is lost, so no metadata is written for the value. This means that if you do not deserialize a strongly typed class or container, you will get the string back, not your original object, and you will return to the square.
You can get around this problem by using a custom ContractResolver, which causes Json.Net to serialize Rect normally instead of using its TypeConverter. Here is the code you need:
class CustomResolver : DefaultContractResolver { protected override JsonContract CreateContract(Type objectType) { if (objectType == typeof(System.Windows.Rect)) return CreateObjectContract(objectType); return base.CreateContract(objectType); } }
Here's a circular demo using the modified code from your question:
JsonSerializer _requestSerializerJson = new JsonSerializer(); _requestSerializerJson.TypeNameHandling = TypeNameHandling.Objects; _requestSerializerJson.ContractResolver = new CustomResolver(); _requestSerializerJson.Formatting = Formatting.Indented; Dictionary<string, object> dictionary = new Dictionary<string, object>(); System.Windows.Rect a = new System.Windows.Rect(1, 2, 3, 4); dictionary.Add("myrect", a); byte[] bytes; using (MemoryStream requestStream = new MemoryStream()) using (var streamWriter = new StreamWriter(requestStream)) using (var writer = new JsonTextWriter(streamWriter)) { _requestSerializerJson.Serialize(writer, dictionary); writer.Flush(); bytes = requestStream.ToArray(); } Console.WriteLine(Encoding.UTF8.GetString(bytes)); Console.WriteLine(); Dictionary<string, object> b; using (MemoryStream stream = new MemoryStream(bytes, 0, bytes.Length)) using (var textReader = new StreamReader(stream)) using (var reader = new JsonTextReader(textReader)) { b = _requestSerializerJson.Deserialize<Dictionary<string, object>>(reader); } System.Windows.Rect rect = (System.Windows.Rect)b["myrect"]; Console.WriteLine("Left: " + rect.Left); Console.WriteLine("Top: " + rect.Top); Console.WriteLine("Width: " + rect.Width); Console.WriteLine("Height: " + rect.Height);
Output:
{ "$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib", "myrect": { "$type": "System.Windows.Rect, WindowsBase", "IsEmpty": false, "Location": "1,2", "Size": "3,4", "X": 1.0, "Y": 2.0, "Width": 3.0, "Height": 4.0, "Left": 1.0, "Top": 2.0, "Right": 4.0, "Bottom": 6.0, "TopLeft": "1,2", "TopRight": "4,2", "BottomLeft": "1,6", "BottomRight": "4,6" } } Left: 1 Top: 2 Width: 3 Height: 4