XmlObjectSerializer.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.Runtime.Serialization
  5. {
  6. using System;
  7. using System.Diagnostics;
  8. using System.Globalization;
  9. using System.IO;
  10. using System.Xml;
  11. using System.Runtime.CompilerServices;
  12. using System.Runtime.Diagnostics;
  13. using System.Text;
  14. using System.Security;
  15. using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
  16. using System.Runtime.Serialization.Diagnostics;
  17. public abstract class XmlObjectSerializer
  18. {
  19. public abstract void WriteStartObject(XmlDictionaryWriter writer, object graph);
  20. public abstract void WriteObjectContent(XmlDictionaryWriter writer, object graph);
  21. public abstract void WriteEndObject(XmlDictionaryWriter writer);
  22. public virtual void WriteObject(Stream stream, object graph)
  23. {
  24. CheckNull(stream, "stream");
  25. XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false /*ownsStream*/);
  26. WriteObject(writer, graph);
  27. writer.Flush();
  28. }
  29. public virtual void WriteObject(XmlWriter writer, object graph)
  30. {
  31. CheckNull(writer, "writer");
  32. WriteObject(XmlDictionaryWriter.CreateDictionaryWriter(writer), graph);
  33. }
  34. public virtual void WriteStartObject(XmlWriter writer, object graph)
  35. {
  36. CheckNull(writer, "writer");
  37. WriteStartObject(XmlDictionaryWriter.CreateDictionaryWriter(writer), graph);
  38. }
  39. public virtual void WriteObjectContent(XmlWriter writer, object graph)
  40. {
  41. CheckNull(writer, "writer");
  42. WriteObjectContent(XmlDictionaryWriter.CreateDictionaryWriter(writer), graph);
  43. }
  44. public virtual void WriteEndObject(XmlWriter writer)
  45. {
  46. CheckNull(writer, "writer");
  47. WriteEndObject(XmlDictionaryWriter.CreateDictionaryWriter(writer));
  48. }
  49. public virtual void WriteObject(XmlDictionaryWriter writer, object graph)
  50. {
  51. WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
  52. }
  53. internal void WriteObjectHandleExceptions(XmlWriterDelegator writer, object graph)
  54. {
  55. WriteObjectHandleExceptions(writer, graph, null);
  56. }
  57. internal void WriteObjectHandleExceptions(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver)
  58. {
  59. try
  60. {
  61. CheckNull(writer, "writer");
  62. if (DiagnosticUtility.ShouldTraceInformation)
  63. {
  64. TraceUtility.Trace(TraceEventType.Information, TraceCode.WriteObjectBegin,
  65. SR.GetString(SR.TraceCodeWriteObjectBegin), new StringTraceRecord("Type", GetTypeInfo(GetSerializeType(graph))));
  66. InternalWriteObject(writer, graph, dataContractResolver);
  67. TraceUtility.Trace(TraceEventType.Information, TraceCode.WriteObjectEnd,
  68. SR.GetString(SR.TraceCodeWriteObjectEnd), new StringTraceRecord("Type", GetTypeInfo(GetSerializeType(graph))));
  69. }
  70. else
  71. {
  72. InternalWriteObject(writer, graph, dataContractResolver);
  73. }
  74. }
  75. catch (XmlException ex)
  76. {
  77. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex));
  78. }
  79. catch (FormatException ex)
  80. {
  81. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex));
  82. }
  83. }
  84. internal virtual DataContractDictionary KnownDataContracts
  85. {
  86. get
  87. {
  88. return null;
  89. }
  90. }
  91. internal virtual void InternalWriteObject(XmlWriterDelegator writer, object graph)
  92. {
  93. WriteStartObject(writer.Writer, graph);
  94. WriteObjectContent(writer.Writer, graph);
  95. WriteEndObject(writer.Writer);
  96. }
  97. internal virtual void InternalWriteObject(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver)
  98. {
  99. InternalWriteObject(writer, graph);
  100. }
  101. internal virtual void InternalWriteStartObject(XmlWriterDelegator writer, object graph)
  102. {
  103. Fx.Assert("XmlObjectSerializer.InternalWriteStartObject should never get called");
  104. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  105. }
  106. internal virtual void InternalWriteObjectContent(XmlWriterDelegator writer, object graph)
  107. {
  108. Fx.Assert("XmlObjectSerializer.InternalWriteObjectContent should never get called");
  109. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  110. }
  111. internal virtual void InternalWriteEndObject(XmlWriterDelegator writer)
  112. {
  113. Fx.Assert("XmlObjectSerializer.InternalWriteEndObject should never get called");
  114. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  115. }
  116. internal void WriteStartObjectHandleExceptions(XmlWriterDelegator writer, object graph)
  117. {
  118. try
  119. {
  120. CheckNull(writer, "writer");
  121. InternalWriteStartObject(writer, graph);
  122. }
  123. catch (XmlException ex)
  124. {
  125. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteStartObject, GetSerializeType(graph), ex), ex));
  126. }
  127. catch (FormatException ex)
  128. {
  129. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteStartObject, GetSerializeType(graph), ex), ex));
  130. }
  131. }
  132. internal void WriteObjectContentHandleExceptions(XmlWriterDelegator writer, object graph)
  133. {
  134. try
  135. {
  136. CheckNull(writer, "writer");
  137. if (DiagnosticUtility.ShouldTraceInformation)
  138. {
  139. TraceUtility.Trace(TraceEventType.Information, TraceCode.WriteObjectContentBegin,
  140. SR.GetString(SR.TraceCodeWriteObjectContentBegin), new StringTraceRecord("Type", GetTypeInfo(GetSerializeType(graph))));
  141. if (writer.WriteState != WriteState.Element)
  142. {
  143. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.XmlWriterMustBeInElement, writer.WriteState)));
  144. }
  145. InternalWriteObjectContent(writer, graph);
  146. TraceUtility.Trace(TraceEventType.Information, TraceCode.WriteObjectContentEnd,
  147. SR.GetString(SR.TraceCodeWriteObjectContentEnd), new StringTraceRecord("Type", GetTypeInfo(GetSerializeType(graph))));
  148. }
  149. else
  150. {
  151. if (writer.WriteState != WriteState.Element)
  152. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.XmlWriterMustBeInElement, writer.WriteState)));
  153. InternalWriteObjectContent(writer, graph);
  154. }
  155. }
  156. catch (XmlException ex)
  157. {
  158. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex));
  159. }
  160. catch (FormatException ex)
  161. {
  162. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex));
  163. }
  164. }
  165. internal void WriteEndObjectHandleExceptions(XmlWriterDelegator writer)
  166. {
  167. try
  168. {
  169. CheckNull(writer, "writer");
  170. InternalWriteEndObject(writer);
  171. }
  172. catch (XmlException ex)
  173. {
  174. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteEndObject, null, ex), ex));
  175. }
  176. catch (FormatException ex)
  177. {
  178. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteEndObject, null, ex), ex));
  179. }
  180. }
  181. internal void WriteRootElement(XmlWriterDelegator writer, DataContract contract, XmlDictionaryString name, XmlDictionaryString ns, bool needsContractNsAtRoot)
  182. {
  183. if (name == null) // root name not set explicitly
  184. {
  185. if (!contract.HasRoot)
  186. return;
  187. contract.WriteRootElement(writer, contract.TopLevelElementName, contract.TopLevelElementNamespace);
  188. }
  189. else
  190. {
  191. contract.WriteRootElement(writer, name, ns);
  192. if (needsContractNsAtRoot)
  193. {
  194. writer.WriteNamespaceDecl(contract.Namespace);
  195. }
  196. }
  197. }
  198. internal bool CheckIfNeedsContractNsAtRoot(XmlDictionaryString name, XmlDictionaryString ns, DataContract contract)
  199. {
  200. if (name == null)
  201. return false;
  202. if (contract.IsBuiltInDataContract || !contract.CanContainReferences || contract.IsISerializable)
  203. return false;
  204. string contractNs = XmlDictionaryString.GetString(contract.Namespace);
  205. if (string.IsNullOrEmpty(contractNs) || contractNs == XmlDictionaryString.GetString(ns))
  206. return false;
  207. return true;
  208. }
  209. internal static void WriteNull(XmlWriterDelegator writer)
  210. {
  211. writer.WriteAttributeBool(Globals.XsiPrefix, DictionaryGlobals.XsiNilLocalName, DictionaryGlobals.SchemaInstanceNamespace, true);
  212. }
  213. internal static bool IsContractDeclared(DataContract contract, DataContract declaredContract)
  214. {
  215. return (object.ReferenceEquals(contract.Name, declaredContract.Name) && object.ReferenceEquals(contract.Namespace, declaredContract.Namespace))
  216. || (contract.Name.Value == declaredContract.Name.Value && contract.Namespace.Value == declaredContract.Namespace.Value);
  217. }
  218. public virtual object ReadObject(Stream stream)
  219. {
  220. CheckNull(stream, "stream");
  221. return ReadObject(XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max));
  222. }
  223. public virtual object ReadObject(XmlReader reader)
  224. {
  225. CheckNull(reader, "reader");
  226. return ReadObject(XmlDictionaryReader.CreateDictionaryReader(reader));
  227. }
  228. public virtual object ReadObject(XmlDictionaryReader reader)
  229. {
  230. return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/);
  231. }
  232. public virtual object ReadObject(XmlReader reader, bool verifyObjectName)
  233. {
  234. CheckNull(reader, "reader");
  235. return ReadObject(XmlDictionaryReader.CreateDictionaryReader(reader), verifyObjectName);
  236. }
  237. public abstract object ReadObject(XmlDictionaryReader reader, bool verifyObjectName);
  238. public virtual bool IsStartObject(XmlReader reader)
  239. {
  240. CheckNull(reader, "reader");
  241. return IsStartObject(XmlDictionaryReader.CreateDictionaryReader(reader));
  242. }
  243. public abstract bool IsStartObject(XmlDictionaryReader reader);
  244. internal virtual object InternalReadObject(XmlReaderDelegator reader, bool verifyObjectName)
  245. {
  246. return ReadObject(reader.UnderlyingReader, verifyObjectName);
  247. }
  248. internal virtual object InternalReadObject(XmlReaderDelegator reader, bool verifyObjectName, DataContractResolver dataContractResolver)
  249. {
  250. return InternalReadObject(reader, verifyObjectName);
  251. }
  252. internal virtual bool InternalIsStartObject(XmlReaderDelegator reader)
  253. {
  254. Fx.Assert("XmlObjectSerializer.InternalIsStartObject should never get called");
  255. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  256. }
  257. internal object ReadObjectHandleExceptions(XmlReaderDelegator reader, bool verifyObjectName)
  258. {
  259. return ReadObjectHandleExceptions(reader, verifyObjectName, null);
  260. }
  261. internal object ReadObjectHandleExceptions(XmlReaderDelegator reader, bool verifyObjectName, DataContractResolver dataContractResolver)
  262. {
  263. try
  264. {
  265. CheckNull(reader, "reader");
  266. if (DiagnosticUtility.ShouldTraceInformation)
  267. {
  268. TraceUtility.Trace(TraceEventType.Information, TraceCode.ReadObjectBegin,
  269. SR.GetString(SR.TraceCodeReadObjectBegin), new StringTraceRecord("Type", GetTypeInfo(GetDeserializeType())));
  270. object retObj = InternalReadObject(reader, verifyObjectName, dataContractResolver);
  271. TraceUtility.Trace(TraceEventType.Information, TraceCode.ReadObjectEnd,
  272. SR.GetString(SR.TraceCodeReadObjectEnd), new StringTraceRecord("Type", GetTypeInfo(GetDeserializeType())));
  273. return retObj;
  274. }
  275. else
  276. {
  277. return InternalReadObject(reader, verifyObjectName, dataContractResolver);
  278. }
  279. }
  280. catch (XmlException ex)
  281. {
  282. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorDeserializing, GetDeserializeType(), ex), ex));
  283. }
  284. catch (FormatException ex)
  285. {
  286. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorDeserializing, GetDeserializeType(), ex), ex));
  287. }
  288. }
  289. internal bool IsStartObjectHandleExceptions(XmlReaderDelegator reader)
  290. {
  291. try
  292. {
  293. CheckNull(reader, "reader");
  294. return InternalIsStartObject(reader);
  295. }
  296. catch (XmlException ex)
  297. {
  298. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorIsStartObject, GetDeserializeType(), ex), ex));
  299. }
  300. catch (FormatException ex)
  301. {
  302. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorIsStartObject, GetDeserializeType(), ex), ex));
  303. }
  304. }
  305. internal bool IsRootXmlAny(XmlDictionaryString rootName, DataContract contract)
  306. {
  307. return (rootName == null) && !contract.HasRoot;
  308. }
  309. internal bool IsStartElement(XmlReaderDelegator reader)
  310. {
  311. return (reader.MoveToElement() || reader.IsStartElement());
  312. }
  313. internal bool IsRootElement(XmlReaderDelegator reader, DataContract contract, XmlDictionaryString name, XmlDictionaryString ns)
  314. {
  315. reader.MoveToElement();
  316. if (name != null) // root name set explicitly
  317. {
  318. return reader.IsStartElement(name, ns);
  319. }
  320. else
  321. {
  322. if (!contract.HasRoot)
  323. return reader.IsStartElement();
  324. if (reader.IsStartElement(contract.TopLevelElementName, contract.TopLevelElementNamespace))
  325. return true;
  326. ClassDataContract classContract = contract as ClassDataContract;
  327. if (classContract != null)
  328. classContract = classContract.BaseContract;
  329. while (classContract != null)
  330. {
  331. if (reader.IsStartElement(classContract.TopLevelElementName, classContract.TopLevelElementNamespace))
  332. return true;
  333. classContract = classContract.BaseContract;
  334. }
  335. if (classContract == null)
  336. {
  337. DataContract objectContract = PrimitiveDataContract.GetPrimitiveDataContract(Globals.TypeOfObject);
  338. if (reader.IsStartElement(objectContract.TopLevelElementName, objectContract.TopLevelElementNamespace))
  339. return true;
  340. }
  341. return false;
  342. }
  343. }
  344. internal static void CheckNull(object obj, string name)
  345. {
  346. if (obj == null)
  347. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(name));
  348. }
  349. internal static string TryAddLineInfo(XmlReaderDelegator reader, string errorMessage)
  350. {
  351. if (reader.HasLineInfo())
  352. return String.Format(CultureInfo.InvariantCulture, "{0} {1}", SR.GetString(SR.ErrorInLine, reader.LineNumber, reader.LinePosition), errorMessage);
  353. return errorMessage;
  354. }
  355. internal static Exception CreateSerializationExceptionWithReaderDetails(string errorMessage, XmlReaderDelegator reader)
  356. {
  357. return XmlObjectSerializer.CreateSerializationException(TryAddLineInfo(reader, SR.GetString(SR.EncounteredWithNameNamespace, errorMessage, reader.NodeType, reader.LocalName, reader.NamespaceURI)));
  358. }
  359. static internal SerializationException CreateSerializationException(string errorMessage)
  360. {
  361. return XmlObjectSerializer.CreateSerializationException(errorMessage, null);
  362. }
  363. [MethodImpl(MethodImplOptions.NoInlining)]
  364. static internal SerializationException CreateSerializationException(string errorMessage, Exception innerException)
  365. {
  366. return new SerializationException(errorMessage, innerException);
  367. }
  368. static string GetTypeInfo(Type type)
  369. {
  370. return (type == null) ? string.Empty : DataContract.GetClrTypeFullName(type);
  371. }
  372. static string GetTypeInfoError(string errorMessage, Type type, Exception innerException)
  373. {
  374. string typeInfo = (type == null) ? string.Empty : SR.GetString(SR.ErrorTypeInfo, DataContract.GetClrTypeFullName(type));
  375. string innerExceptionMessage = (innerException == null) ? string.Empty : innerException.Message;
  376. return SR.GetString(errorMessage, typeInfo, innerExceptionMessage);
  377. }
  378. internal virtual Type GetSerializeType(object graph)
  379. {
  380. return (graph == null) ? null : graph.GetType();
  381. }
  382. internal virtual Type GetDeserializeType()
  383. {
  384. return null;
  385. }
  386. [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
  387. [SecurityCritical]
  388. static IFormatterConverter formatterConverter;
  389. static internal IFormatterConverter FormatterConverter
  390. {
  391. [Fx.Tag.SecurityNote(Critical = "Fetches the critical formatterConverter field.",
  392. Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")]
  393. [SecuritySafeCritical]
  394. get
  395. {
  396. if (formatterConverter == null)
  397. formatterConverter = new FormatterConverter();
  398. return formatterConverter;
  399. }
  400. }
  401. }
  402. }