DataContractSerializer and dictionary <string, object> do not work when reading

I am using a DataContractSerializer to serialize an object containing a Dictionary<string,object> element that is marked [DataMember()] . The idea is to have a flexible bag of attributes for an object, and I don't know what these attributes can be.

This works fine when I put int , double and string objects in the dictionary, but when I put a List<string> , it cannot deserialize the object with

 System.InvalidOperationException: Node type Element is not supported in this operation. 

The entire dictionary is serialized in XML, and it looks pretty reasonable:

 <Attributes xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <d2p1:KeyValueOfstringanyType> <d2p1:Key>name</d2p1:Key> <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">Test object</d2p1:Value> </d2p1:KeyValueOfstringanyType> <d2p1:KeyValueOfstringanyType> <d2p1:Key>x</d2p1:Key> <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:double">0.5</d2p1:Value> </d2p1:KeyValueOfstringanyType> <d2p1:KeyValueOfstringanyType> <d2p1:Key>y</d2p1:Key> <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:double">1.25</d2p1:Value> </d2p1:KeyValueOfstringanyType> <d2p1:KeyValueOfstringanyType> <d2p1:Key>age</d2p1:Key> <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:int">4</d2p1:Value> </d2p1:KeyValueOfstringanyType> <d2p1:KeyValueOfstringanyType> <d2p1:Key>list-of-strings</d2p1:Key> <d2p1:Value> <d2p1:string>one string</d2p1:string> <d2p1:string>two string</d2p1:string> <d2p1:string>last string</d2p1:string> </d2p1:Value> </d2p1:KeyValueOfstringanyType> </Attributes> 

Note the list-of-strings at the end. He got all the values, but says nothing about whether it is a List<string> or something else.

What is the right way to deal with this situation?

+6
source share
2 answers

Try using KnownTypeAttribute so that the DataContractSerializer knows about the List<string> . Unfortunately, this seems to contradict your idea of ​​not knowing about types before you get started.

I base this on the following code that uses the DataContractSerializer to serialize a Dictionary<string, object> containing a List<string> :

 Dictionary<string,object> dictionary = new Dictionary<string, object>(); dictionary.Add("k1", new List<string> { "L1", "L2", "L3" }); List<Type> knownTypes = new List<Type> { typeof(List<string>) }; DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string,object>), knownTypes); MemoryStream stream = new MemoryStream(); serializer.WriteObject(stream, dictionary); StreamReader reader = new StreamReader(stream); stream.Position = 0; string xml = reader.ReadToEnd(); 

If you knownTypes not provided by DataContractSerializer , it throws an exception.

SerializationException: Type 'System.Collections.Generic.List`1 [[System.String, mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]]' with the name of the data contract 'ArrayOfString: HTTP: // schemas .microsoft.com / 2003/10 / Serialization / Arrays' is not expected. Consider using a DataContractResolver or add types that are not statically unknown to the list of known types — for example, using the KnownTypeAttribute attribute or adding them to the list of known types passed to the DataContractSerializer.

+8
source

WCF does not know that you have a List<string> there - note that all other <Value> elements have a "hint type" (attribute i: type). If you want to deserialize it, it must be labeled, and you also need to tell WCF that the List<string> is a "known type" - see below. For more information about known types (and why they are needed), there are many resources on the web .

 public class StackOverflow_7620718 { public static void Test() { Dictionary<string, object> dict = new Dictionary<string, object> { { "name", "Test object" }, { "x", 0.5 }, { "y", 1.25 }, { "age", 4 }, { "list-of-strings", new List<string> { "one string", "two string", "last string" } } }; MemoryStream ms = new MemoryStream(); XmlWriter w = XmlWriter.Create(ms, new XmlWriterSettings { Indent = true, Encoding = new UTF8Encoding(false), IndentChars = " ", OmitXmlDeclaration = true, }); DataContractSerializer dcs = new DataContractSerializer(dict.GetType(), new Type[] { typeof(List<string>) }); dcs.WriteObject(w, dict); w.Flush(); Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray())); ms.Position = 0; Console.WriteLine("Now deserializing it:"); Dictionary<string, object> dict2 = (Dictionary<string, object>)dcs.ReadObject(ms); foreach (var key in dict2.Keys) { Console.WriteLine("{0}: {1}", key, dict2[key].GetType().Name); } } } 
0
source

Source: https://habr.com/ru/post/898443/


All Articles