DataContractSerializer.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.Runtime.Serialization
  5. {
  6. using System;
  7. using System.Collections;
  8. using System.Diagnostics;
  9. using System.Globalization;
  10. using System.IO;
  11. using System.Reflection;
  12. using System.Text;
  13. using System.Xml;
  14. using System.Xml.Serialization;
  15. using System.Collections.Generic;
  16. using System.Collections.ObjectModel;
  17. using System.Runtime.CompilerServices;
  18. using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
  19. public sealed class DataContractSerializer : XmlObjectSerializer
  20. {
  21. Type rootType;
  22. DataContract rootContract; // post-surrogate
  23. bool needsContractNsAtRoot;
  24. XmlDictionaryString rootName;
  25. XmlDictionaryString rootNamespace;
  26. int maxItemsInObjectGraph;
  27. bool ignoreExtensionDataObject;
  28. bool preserveObjectReferences;
  29. IDataContractSurrogate dataContractSurrogate;
  30. ReadOnlyCollection<Type> knownTypeCollection;
  31. internal IList<Type> knownTypeList;
  32. internal DataContractDictionary knownDataContracts;
  33. DataContractResolver dataContractResolver;
  34. bool serializeReadOnlyTypes;
  35. public DataContractSerializer(Type type)
  36. : this(type, (IEnumerable<Type>)null)
  37. {
  38. }
  39. public DataContractSerializer(Type type, IEnumerable<Type> knownTypes)
  40. : this(type, knownTypes, int.MaxValue, false, false, null)
  41. {
  42. }
  43. public DataContractSerializer(Type type,
  44. IEnumerable<Type> knownTypes,
  45. int maxItemsInObjectGraph,
  46. bool ignoreExtensionDataObject,
  47. bool preserveObjectReferences,
  48. IDataContractSurrogate dataContractSurrogate)
  49. : this(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, null)
  50. {
  51. }
  52. public DataContractSerializer(Type type,
  53. IEnumerable<Type> knownTypes,
  54. int maxItemsInObjectGraph,
  55. bool ignoreExtensionDataObject,
  56. bool preserveObjectReferences,
  57. IDataContractSurrogate dataContractSurrogate,
  58. DataContractResolver dataContractResolver)
  59. {
  60. Initialize(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, false);
  61. }
  62. public DataContractSerializer(Type type, string rootName, string rootNamespace)
  63. : this(type, rootName, rootNamespace, null)
  64. {
  65. }
  66. public DataContractSerializer(Type type, string rootName, string rootNamespace, IEnumerable<Type> knownTypes)
  67. : this(type, rootName, rootNamespace, knownTypes, int.MaxValue, false, false, null)
  68. {
  69. }
  70. public DataContractSerializer(Type type, string rootName, string rootNamespace,
  71. IEnumerable<Type> knownTypes,
  72. int maxItemsInObjectGraph,
  73. bool ignoreExtensionDataObject,
  74. bool preserveObjectReferences,
  75. IDataContractSurrogate dataContractSurrogate)
  76. : this(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, null)
  77. {
  78. }
  79. public DataContractSerializer(Type type, string rootName, string rootNamespace,
  80. IEnumerable<Type> knownTypes,
  81. int maxItemsInObjectGraph,
  82. bool ignoreExtensionDataObject,
  83. bool preserveObjectReferences,
  84. IDataContractSurrogate dataContractSurrogate,
  85. DataContractResolver dataContractResolver)
  86. {
  87. XmlDictionary dictionary = new XmlDictionary(2);
  88. Initialize(type, dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, false);
  89. }
  90. public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace)
  91. : this(type, rootName, rootNamespace, null)
  92. {
  93. }
  94. public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, IEnumerable<Type> knownTypes)
  95. : this(type, rootName, rootNamespace, knownTypes, int.MaxValue, false, false, null, null)
  96. {
  97. }
  98. public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
  99. IEnumerable<Type> knownTypes,
  100. int maxItemsInObjectGraph,
  101. bool ignoreExtensionDataObject,
  102. bool preserveObjectReferences,
  103. IDataContractSurrogate dataContractSurrogate)
  104. : this(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, null)
  105. {
  106. }
  107. public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
  108. IEnumerable<Type> knownTypes,
  109. int maxItemsInObjectGraph,
  110. bool ignoreExtensionDataObject,
  111. bool preserveObjectReferences,
  112. IDataContractSurrogate dataContractSurrogate,
  113. DataContractResolver dataContractResolver)
  114. {
  115. Initialize(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, false);
  116. }
  117. public DataContractSerializer(Type type, DataContractSerializerSettings settings)
  118. {
  119. if (settings == null)
  120. {
  121. settings = new DataContractSerializerSettings();
  122. }
  123. Initialize(type, settings.RootName, settings.RootNamespace, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject,
  124. settings.PreserveObjectReferences, settings.DataContractSurrogate, settings.DataContractResolver, settings.SerializeReadOnlyTypes);
  125. }
  126. void Initialize(Type type,
  127. IEnumerable<Type> knownTypes,
  128. int maxItemsInObjectGraph,
  129. bool ignoreExtensionDataObject,
  130. bool preserveObjectReferences,
  131. IDataContractSurrogate dataContractSurrogate,
  132. DataContractResolver dataContractResolver,
  133. bool serializeReadOnlyTypes)
  134. {
  135. CheckNull(type, "type");
  136. this.rootType = type;
  137. if (knownTypes != null)
  138. {
  139. this.knownTypeList = new List<Type>();
  140. foreach (Type knownType in knownTypes)
  141. {
  142. this.knownTypeList.Add(knownType);
  143. }
  144. }
  145. if (maxItemsInObjectGraph < 0)
  146. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxItemsInObjectGraph", SR.GetString(SR.ValueMustBeNonNegative)));
  147. this.maxItemsInObjectGraph = maxItemsInObjectGraph;
  148. this.ignoreExtensionDataObject = ignoreExtensionDataObject;
  149. this.preserveObjectReferences = preserveObjectReferences;
  150. this.dataContractSurrogate = dataContractSurrogate;
  151. this.dataContractResolver = dataContractResolver;
  152. this.serializeReadOnlyTypes = serializeReadOnlyTypes;
  153. }
  154. void Initialize(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
  155. IEnumerable<Type> knownTypes,
  156. int maxItemsInObjectGraph,
  157. bool ignoreExtensionDataObject,
  158. bool preserveObjectReferences,
  159. IDataContractSurrogate dataContractSurrogate,
  160. DataContractResolver dataContractResolver,
  161. bool serializeReadOnlyTypes)
  162. {
  163. Initialize(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, serializeReadOnlyTypes);
  164. // validate root name and namespace are both non-null
  165. this.rootName = rootName;
  166. this.rootNamespace = rootNamespace;
  167. }
  168. public ReadOnlyCollection<Type> KnownTypes
  169. {
  170. get
  171. {
  172. if (knownTypeCollection == null)
  173. {
  174. if (knownTypeList != null)
  175. {
  176. knownTypeCollection = new ReadOnlyCollection<Type>(knownTypeList);
  177. }
  178. else
  179. {
  180. knownTypeCollection = new ReadOnlyCollection<Type>(Globals.EmptyTypeArray);
  181. }
  182. }
  183. return knownTypeCollection;
  184. }
  185. }
  186. internal override DataContractDictionary KnownDataContracts
  187. {
  188. get
  189. {
  190. if (this.knownDataContracts == null && this.knownTypeList != null)
  191. {
  192. // This assignment may be performed concurrently and thus is a race condition.
  193. // It's safe, however, because at worse a new (and identical) dictionary of
  194. // data contracts will be created and re-assigned to this field. Introduction
  195. // of a lock here could lead to deadlocks.
  196. this.knownDataContracts = XmlObjectSerializerContext.GetDataContractsForKnownTypes(this.knownTypeList);
  197. }
  198. return this.knownDataContracts;
  199. }
  200. }
  201. public int MaxItemsInObjectGraph
  202. {
  203. get { return maxItemsInObjectGraph; }
  204. }
  205. public IDataContractSurrogate DataContractSurrogate
  206. {
  207. get { return dataContractSurrogate; }
  208. }
  209. public bool PreserveObjectReferences
  210. {
  211. get { return preserveObjectReferences; }
  212. }
  213. public bool IgnoreExtensionDataObject
  214. {
  215. get { return ignoreExtensionDataObject; }
  216. }
  217. public DataContractResolver DataContractResolver
  218. {
  219. get { return dataContractResolver; }
  220. }
  221. public bool SerializeReadOnlyTypes
  222. {
  223. get { return serializeReadOnlyTypes; }
  224. }
  225. DataContract RootContract
  226. {
  227. get
  228. {
  229. if (rootContract == null)
  230. {
  231. rootContract = DataContract.GetDataContract(((dataContractSurrogate == null) ? rootType : GetSurrogatedType(dataContractSurrogate, rootType)));
  232. needsContractNsAtRoot = CheckIfNeedsContractNsAtRoot(rootName, rootNamespace, rootContract);
  233. }
  234. return rootContract;
  235. }
  236. }
  237. internal override void InternalWriteObject(XmlWriterDelegator writer, object graph)
  238. {
  239. InternalWriteObject(writer, graph, null);
  240. }
  241. internal override void InternalWriteObject(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver)
  242. {
  243. InternalWriteStartObject(writer, graph);
  244. InternalWriteObjectContent(writer, graph, dataContractResolver);
  245. InternalWriteEndObject(writer);
  246. }
  247. public override void WriteObject(XmlWriter writer, object graph)
  248. {
  249. WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
  250. }
  251. public override void WriteStartObject(XmlWriter writer, object graph)
  252. {
  253. WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
  254. }
  255. public override void WriteObjectContent(XmlWriter writer, object graph)
  256. {
  257. WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
  258. }
  259. public override void WriteEndObject(XmlWriter writer)
  260. {
  261. WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
  262. }
  263. public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
  264. {
  265. WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
  266. }
  267. public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
  268. {
  269. WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
  270. }
  271. public override void WriteEndObject(XmlDictionaryWriter writer)
  272. {
  273. WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
  274. }
  275. public void WriteObject(XmlDictionaryWriter writer, object graph, DataContractResolver dataContractResolver)
  276. {
  277. WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph, dataContractResolver);
  278. }
  279. public override object ReadObject(XmlReader reader)
  280. {
  281. return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/);
  282. }
  283. public override object ReadObject(XmlReader reader, bool verifyObjectName)
  284. {
  285. return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
  286. }
  287. public override bool IsStartObject(XmlReader reader)
  288. {
  289. return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
  290. }
  291. public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
  292. {
  293. return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
  294. }
  295. public override bool IsStartObject(XmlDictionaryReader reader)
  296. {
  297. return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
  298. }
  299. public object ReadObject(XmlDictionaryReader reader, bool verifyObjectName, DataContractResolver dataContractResolver)
  300. {
  301. return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName, dataContractResolver);
  302. }
  303. internal override void InternalWriteStartObject(XmlWriterDelegator writer, object graph)
  304. {
  305. WriteRootElement(writer, RootContract, rootName, rootNamespace, needsContractNsAtRoot);
  306. }
  307. internal override void InternalWriteObjectContent(XmlWriterDelegator writer, object graph)
  308. {
  309. InternalWriteObjectContent(writer, graph, null);
  310. }
  311. internal void InternalWriteObjectContent(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver)
  312. {
  313. if (MaxItemsInObjectGraph == 0)
  314. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
  315. DataContract contract = RootContract;
  316. Type declaredType = contract.UnderlyingType;
  317. Type graphType = (graph == null) ? declaredType : graph.GetType();
  318. if (dataContractSurrogate != null)
  319. graph = SurrogateToDataContractType(dataContractSurrogate, graph, declaredType, ref graphType);
  320. if (dataContractResolver == null)
  321. dataContractResolver = this.DataContractResolver;
  322. if (graph == null)
  323. {
  324. if (IsRootXmlAny(rootName, contract))
  325. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsAnyCannotBeNull, declaredType)));
  326. WriteNull(writer);
  327. }
  328. else
  329. {
  330. if (declaredType == graphType)
  331. {
  332. if (contract.CanContainReferences)
  333. {
  334. XmlObjectSerializerWriteContext context = XmlObjectSerializerWriteContext.CreateContext(this, contract, dataContractResolver);
  335. context.HandleGraphAtTopLevel(writer, graph, contract);
  336. context.SerializeWithoutXsiType(contract, writer, graph, declaredType.TypeHandle);
  337. }
  338. else
  339. {
  340. contract.WriteXmlValue(writer, graph, null);
  341. }
  342. }
  343. else
  344. {
  345. XmlObjectSerializerWriteContext context = null;
  346. if (IsRootXmlAny(rootName, contract))
  347. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsAnyCannotBeSerializedAsDerivedType, graphType, contract.UnderlyingType)));
  348. contract = GetDataContract(contract, declaredType, graphType);
  349. context = XmlObjectSerializerWriteContext.CreateContext(this, RootContract, dataContractResolver);
  350. if (contract.CanContainReferences)
  351. {
  352. context.HandleGraphAtTopLevel(writer, graph, contract);
  353. }
  354. context.OnHandleIsReference(writer, contract, graph);
  355. context.SerializeWithXsiTypeAtTopLevel(contract, writer, graph, declaredType.TypeHandle, graphType);
  356. }
  357. }
  358. }
  359. internal static DataContract GetDataContract(DataContract declaredTypeContract, Type declaredType, Type objectType)
  360. {
  361. if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType))
  362. {
  363. return declaredTypeContract;
  364. }
  365. else if (declaredType.IsArray)//Array covariance is not supported in XSD
  366. {
  367. return declaredTypeContract;
  368. }
  369. else
  370. {
  371. return DataContract.GetDataContract(objectType.TypeHandle, objectType, SerializationMode.SharedContract);
  372. }
  373. }
  374. internal override void InternalWriteEndObject(XmlWriterDelegator writer)
  375. {
  376. if (!IsRootXmlAny(rootName, RootContract))
  377. {
  378. writer.WriteEndElement();
  379. }
  380. }
  381. internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName)
  382. {
  383. return InternalReadObject(xmlReader, verifyObjectName, null);
  384. }
  385. internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName, DataContractResolver dataContractResolver)
  386. {
  387. if (MaxItemsInObjectGraph == 0)
  388. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
  389. if (dataContractResolver == null)
  390. dataContractResolver = this.DataContractResolver;
  391. if (verifyObjectName)
  392. {
  393. if (!InternalIsStartObject(xmlReader))
  394. {
  395. XmlDictionaryString expectedName;
  396. XmlDictionaryString expectedNs;
  397. if (rootName == null)
  398. {
  399. expectedName = RootContract.TopLevelElementName;
  400. expectedNs = RootContract.TopLevelElementNamespace;
  401. }
  402. else
  403. {
  404. expectedName = rootName;
  405. expectedNs = rootNamespace;
  406. }
  407. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.GetString(SR.ExpectingElement, expectedNs, expectedName), xmlReader));
  408. }
  409. }
  410. else if (!IsStartElement(xmlReader))
  411. {
  412. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.GetString(SR.ExpectingElementAtDeserialize, XmlNodeType.Element), xmlReader));
  413. }
  414. DataContract contract = RootContract;
  415. if (contract.IsPrimitive && object.ReferenceEquals(contract.UnderlyingType, rootType) /*handle Nullable<T> differently*/)
  416. {
  417. return contract.ReadXmlValue(xmlReader, null);
  418. }
  419. if (IsRootXmlAny(rootName, contract))
  420. {
  421. return XmlObjectSerializerReadContext.ReadRootIXmlSerializable(xmlReader, contract as XmlDataContract, false /*isMemberType*/);
  422. }
  423. XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext.CreateContext(this, contract, dataContractResolver);
  424. return context.InternalDeserialize(xmlReader, rootType, contract, null, null);
  425. }
  426. internal override bool InternalIsStartObject(XmlReaderDelegator reader)
  427. {
  428. return IsRootElement(reader, RootContract, rootName, rootNamespace);
  429. }
  430. internal override Type GetSerializeType(object graph)
  431. {
  432. return (graph == null) ? rootType : graph.GetType();
  433. }
  434. internal override Type GetDeserializeType()
  435. {
  436. return rootType;
  437. }
  438. internal static object SurrogateToDataContractType(IDataContractSurrogate dataContractSurrogate, object oldObj, Type surrogatedDeclaredType, ref Type objType)
  439. {
  440. object obj = DataContractSurrogateCaller.GetObjectToSerialize(dataContractSurrogate, oldObj, objType, surrogatedDeclaredType);
  441. if (obj != oldObj)
  442. {
  443. if (obj == null)
  444. objType = Globals.TypeOfObject;
  445. else
  446. objType = obj.GetType();
  447. }
  448. return obj;
  449. }
  450. internal static Type GetSurrogatedType(IDataContractSurrogate dataContractSurrogate, Type type)
  451. {
  452. return DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, DataContract.UnwrapNullableType(type));
  453. }
  454. }
  455. }