XmlSerializer.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. //
  2. // XmlSerializer.cs:
  3. //
  4. // Author:
  5. // Lluis Sanchez Gual ([email protected])
  6. //
  7. // (C) 2002, 2003 Ximian, Inc. http://www.ximian.com
  8. //
  9. using System;
  10. using System.Threading;
  11. using System.Collections;
  12. using System.IO;
  13. using System.Reflection;
  14. using System.Xml;
  15. using System.Xml.Schema;
  16. using System.Text;
  17. using System.CodeDom;
  18. using System.CodeDom.Compiler;
  19. using Microsoft.CSharp;
  20. using System.Configuration;
  21. namespace System.Xml.Serialization
  22. {
  23. public class XmlSerializer
  24. {
  25. internal const string WsdlNamespace = "http://schemas.xmlsoap.org/wsdl/";
  26. internal const string EncodingNamespace = "http://schemas.xmlsoap.org/soap/encoding/";
  27. static int generationThreshold;
  28. static bool backgroundGeneration = true;
  29. static bool deleteTempFiles = true;
  30. bool customSerializer;
  31. XmlMapping typeMapping;
  32. SerializerData serializerData;
  33. Type writerType;
  34. Type readerType;
  35. static Hashtable serializerTypes = new Hashtable ();
  36. internal class SerializerData
  37. {
  38. public int UsageCount;
  39. public Type ReaderType;
  40. public MethodInfo ReaderMethod;
  41. public Type WriterType;
  42. public MethodInfo WriterMethod;
  43. public GenerationBatch Batch;
  44. }
  45. internal class GenerationBatch
  46. {
  47. public bool Done;
  48. public XmlMapping[] Maps;
  49. public SerializerData[] Datas;
  50. }
  51. static XmlSerializer ()
  52. {
  53. IDictionary table = (IDictionary) ConfigurationSettings.GetConfig("system.diagnostics");
  54. if (table != null) {
  55. table = (IDictionary) table["switches"];
  56. if (table != null) {
  57. string val = (string) table ["XmlSerialization.Compilation"];
  58. if (val == "1") deleteTempFiles = false;
  59. }
  60. }
  61. string th = Environment.GetEnvironmentVariable ("MONO_XMLSERIALIZER_THS");
  62. if (th == null) {
  63. generationThreshold = -1;
  64. backgroundGeneration = false;
  65. }
  66. else if (th.ToLower() == "no")
  67. generationThreshold = -1;
  68. else {
  69. generationThreshold = int.Parse (th);
  70. backgroundGeneration = (generationThreshold != 0);
  71. if (generationThreshold < 1) generationThreshold = 1;
  72. }
  73. }
  74. #region Constructors
  75. protected XmlSerializer ()
  76. {
  77. customSerializer = true;
  78. }
  79. public XmlSerializer (Type type)
  80. : this (type, null, null, null, null)
  81. {
  82. }
  83. public XmlSerializer (XmlTypeMapping xmlTypeMapping)
  84. {
  85. typeMapping = xmlTypeMapping;
  86. }
  87. internal XmlSerializer (XmlMapping mapping, SerializerData data)
  88. {
  89. typeMapping = mapping;
  90. serializerData = data;
  91. }
  92. public XmlSerializer (Type type, string defaultNamespace)
  93. : this (type, null, null, null, defaultNamespace)
  94. {
  95. }
  96. public XmlSerializer (Type type, Type[] extraTypes)
  97. : this (type, null, extraTypes, null, null)
  98. {
  99. }
  100. public XmlSerializer (Type type, XmlAttributeOverrides overrides)
  101. : this (type, overrides, null, null, null)
  102. {
  103. }
  104. public XmlSerializer (Type type, XmlRootAttribute root)
  105. : this (type, null, null, root, null)
  106. {
  107. }
  108. public XmlSerializer (Type type,
  109. XmlAttributeOverrides overrides,
  110. Type [] extraTypes,
  111. XmlRootAttribute root,
  112. string defaultNamespace)
  113. {
  114. if (type == null)
  115. throw new ArgumentNullException ("type");
  116. XmlReflectionImporter importer = new XmlReflectionImporter (overrides, defaultNamespace);
  117. if (extraTypes != null)
  118. {
  119. foreach (Type intype in extraTypes)
  120. importer.IncludeType (intype);
  121. }
  122. typeMapping = importer.ImportTypeMapping (type, root, defaultNamespace);
  123. }
  124. #endregion // Constructors
  125. #region Events
  126. private XmlAttributeEventHandler onUnknownAttribute;
  127. private XmlElementEventHandler onUnknownElement;
  128. private XmlNodeEventHandler onUnknownNode;
  129. private UnreferencedObjectEventHandler onUnreferencedObject;
  130. public event XmlAttributeEventHandler UnknownAttribute
  131. {
  132. add { onUnknownAttribute += value; } remove { onUnknownAttribute -= value; }
  133. }
  134. public event XmlElementEventHandler UnknownElement
  135. {
  136. add { onUnknownElement += value; } remove { onUnknownElement -= value; }
  137. }
  138. public event XmlNodeEventHandler UnknownNode
  139. {
  140. add { onUnknownNode += value; } remove { onUnknownNode -= value; }
  141. }
  142. public event UnreferencedObjectEventHandler UnreferencedObject
  143. {
  144. add { onUnreferencedObject += value; } remove { onUnreferencedObject -= value; }
  145. }
  146. internal virtual void OnUnknownAttribute (XmlAttributeEventArgs e)
  147. {
  148. if (onUnknownAttribute != null) onUnknownAttribute(this, e);
  149. }
  150. internal virtual void OnUnknownElement (XmlElementEventArgs e)
  151. {
  152. if (onUnknownElement != null) onUnknownElement(this, e);
  153. }
  154. internal virtual void OnUnknownNode (XmlNodeEventArgs e)
  155. {
  156. if (onUnknownNode != null) onUnknownNode(this, e);
  157. }
  158. internal virtual void OnUnreferencedObject (UnreferencedObjectEventArgs e)
  159. {
  160. if (onUnreferencedObject != null) onUnreferencedObject(this, e);
  161. }
  162. #endregion // Events
  163. #region Methods
  164. public virtual bool CanDeserialize (XmlReader xmlReader)
  165. {
  166. xmlReader.MoveToContent ();
  167. if (typeMapping is XmlMembersMapping)
  168. return true;
  169. else
  170. return ((XmlTypeMapping)typeMapping).ElementName == xmlReader.LocalName;
  171. }
  172. protected virtual XmlSerializationReader CreateReader ()
  173. {
  174. // Must be implemented in derived class
  175. throw new NotImplementedException ();
  176. }
  177. protected virtual XmlSerializationWriter CreateWriter ()
  178. {
  179. // Must be implemented in derived class
  180. throw new NotImplementedException ();
  181. }
  182. public object Deserialize (Stream stream)
  183. {
  184. XmlTextReader xmlReader = new XmlTextReader(stream);
  185. return Deserialize(xmlReader);
  186. }
  187. public object Deserialize (TextReader textReader)
  188. {
  189. XmlTextReader xmlReader = new XmlTextReader(textReader);
  190. return Deserialize(xmlReader);
  191. }
  192. public object Deserialize (XmlReader xmlReader)
  193. {
  194. XmlSerializationReader xsReader;
  195. if (customSerializer)
  196. xsReader = CreateReader ();
  197. else
  198. xsReader = CreateReader (typeMapping);
  199. xsReader.Initialize (xmlReader, this);
  200. return Deserialize (xsReader);
  201. }
  202. protected virtual object Deserialize (XmlSerializationReader reader)
  203. {
  204. if (customSerializer)
  205. // Must be implemented in derived class
  206. throw new NotImplementedException ();
  207. if (reader is XmlSerializationReaderInterpreter)
  208. return ((XmlSerializationReaderInterpreter)reader).ReadRoot ();
  209. else
  210. return serializerData.ReaderMethod.Invoke (reader, null);
  211. }
  212. public static XmlSerializer [] FromMappings (XmlMapping [] mappings)
  213. {
  214. XmlSerializer[] sers = new XmlSerializer [mappings.Length];
  215. SerializerData[] datas = new SerializerData [mappings.Length];
  216. GenerationBatch batch = new GenerationBatch ();
  217. batch.Maps = mappings;
  218. batch.Datas = datas;
  219. for (int n=0; n<mappings.Length; n++)
  220. {
  221. if (mappings[n] != null)
  222. {
  223. SerializerData data = new SerializerData ();
  224. data.Batch = batch;
  225. sers[n] = new XmlSerializer (mappings[n], data);
  226. datas[n] = data;
  227. }
  228. }
  229. return sers;
  230. }
  231. public static XmlSerializer [] FromTypes (Type [] mappings)
  232. {
  233. XmlSerializer [] sers = new XmlSerializer [mappings.Length];
  234. for (int n=0; n<mappings.Length; n++)
  235. sers[n] = new XmlSerializer (mappings[n]);
  236. return sers;
  237. }
  238. protected virtual void Serialize (object o, XmlSerializationWriter writer)
  239. {
  240. if (customSerializer)
  241. // Must be implemented in derived class
  242. throw new NotImplementedException ();
  243. if (writer is XmlSerializationWriterInterpreter)
  244. ((XmlSerializationWriterInterpreter)writer).WriteRoot (o);
  245. else
  246. serializerData.WriterMethod.Invoke (writer, new object[] {o});
  247. }
  248. public void Serialize (Stream stream, object o)
  249. {
  250. XmlTextWriter xmlWriter = new XmlTextWriter (stream, System.Text.Encoding.Default);
  251. xmlWriter.Formatting = Formatting.Indented;
  252. Serialize (xmlWriter, o, null);
  253. }
  254. public void Serialize (TextWriter textWriter, object o)
  255. {
  256. XmlTextWriter xmlWriter = new XmlTextWriter (textWriter);
  257. xmlWriter.Formatting = Formatting.Indented;
  258. Serialize (xmlWriter, o, null);
  259. }
  260. public void Serialize (XmlWriter xmlWriter, object o)
  261. {
  262. Serialize (xmlWriter, o, null);
  263. }
  264. public void Serialize (Stream stream, object o, XmlSerializerNamespaces namespaces)
  265. {
  266. XmlTextWriter xmlWriter = new XmlTextWriter (stream, System.Text.Encoding.Default);
  267. xmlWriter.Formatting = Formatting.Indented;
  268. Serialize (xmlWriter, o, namespaces);
  269. }
  270. public void Serialize (TextWriter textWriter, object o, XmlSerializerNamespaces namespaces)
  271. {
  272. XmlTextWriter xmlWriter = new XmlTextWriter (textWriter);
  273. xmlWriter.Formatting = Formatting.Indented;
  274. Serialize (xmlWriter, o, namespaces);
  275. xmlWriter.Flush();
  276. }
  277. public void Serialize (XmlWriter writer, object o, XmlSerializerNamespaces namespaces)
  278. {
  279. XmlSerializationWriter xsWriter;
  280. if (customSerializer)
  281. xsWriter = CreateWriter ();
  282. else
  283. xsWriter = CreateWriter (typeMapping);
  284. if (namespaces == null || namespaces.Count == 0)
  285. {
  286. namespaces = new XmlSerializerNamespaces ();
  287. namespaces.Add ("xsd", XmlSchema.Namespace);
  288. namespaces.Add ("xsi", XmlSchema.InstanceNamespace);
  289. }
  290. xsWriter.Initialize (writer, namespaces);
  291. Serialize (o, xsWriter);
  292. writer.Flush ();
  293. }
  294. XmlSerializationWriter CreateWriter (XmlMapping typeMapping)
  295. {
  296. lock (this) {
  297. if (serializerData != null && serializerData.WriterType != null)
  298. return (XmlSerializationWriter) Activator.CreateInstance (serializerData.WriterType);
  299. }
  300. if (!typeMapping.Source.CanBeGenerated || generationThreshold == -1)
  301. return new XmlSerializationWriterInterpreter (typeMapping);
  302. CheckGeneratedTypes (typeMapping);
  303. lock (this) {
  304. if (serializerData.WriterType != null)
  305. return (XmlSerializationWriter) Activator.CreateInstance (serializerData.WriterType);
  306. }
  307. return new XmlSerializationWriterInterpreter (typeMapping);
  308. }
  309. XmlSerializationReader CreateReader (XmlMapping typeMapping)
  310. {
  311. lock (this) {
  312. if (serializerData != null && serializerData.ReaderType != null)
  313. return (XmlSerializationReader) Activator.CreateInstance (serializerData.ReaderType);
  314. }
  315. if (!typeMapping.Source.CanBeGenerated || generationThreshold == -1)
  316. return new XmlSerializationReaderInterpreter (typeMapping);
  317. CheckGeneratedTypes (typeMapping);
  318. lock (this) {
  319. if (serializerData.ReaderType != null)
  320. return (XmlSerializationReader) Activator.CreateInstance (serializerData.ReaderType);
  321. }
  322. return new XmlSerializationReaderInterpreter (typeMapping);
  323. }
  324. void CheckGeneratedTypes (XmlMapping typeMapping)
  325. {
  326. lock (this)
  327. {
  328. if (serializerData == null)
  329. {
  330. lock (serializerTypes)
  331. {
  332. serializerData = (SerializerData) serializerTypes [typeMapping.Source];
  333. if (serializerData == null) {
  334. serializerData = new SerializerData();
  335. serializerTypes [typeMapping.Source] = serializerData;
  336. }
  337. }
  338. }
  339. }
  340. bool generate = false;
  341. lock (serializerData)
  342. {
  343. generate = (++serializerData.UsageCount == generationThreshold);
  344. }
  345. if (generate)
  346. {
  347. if (serializerData.Batch != null)
  348. GenerateSerializers (serializerData.Batch);
  349. else
  350. {
  351. GenerationBatch batch = new GenerationBatch ();
  352. batch.Maps = new XmlMapping[] {typeMapping};
  353. batch.Datas = new SerializerData[] {serializerData};
  354. GenerateSerializers (batch);
  355. }
  356. }
  357. }
  358. void GenerateSerializers (GenerationBatch batch)
  359. {
  360. if (batch.Maps.Length != batch.Datas.Length)
  361. throw new ArgumentException ("batch");
  362. lock (batch)
  363. {
  364. if (batch.Done) return;
  365. batch.Done = true;
  366. }
  367. if (backgroundGeneration)
  368. ThreadPool.QueueUserWorkItem (new WaitCallback (RunSerializerGeneration), batch);
  369. else
  370. RunSerializerGeneration (batch);
  371. }
  372. void RunSerializerGeneration (object obj)
  373. {
  374. try
  375. {
  376. RunSerializerGenerationAux (obj);
  377. }
  378. catch (Exception ex)
  379. {
  380. Console.WriteLine (ex);
  381. }
  382. }
  383. void RunSerializerGenerationAux (object obj)
  384. {
  385. DateTime tim = DateTime.Now;
  386. GenerationBatch batch = (GenerationBatch) obj;
  387. XmlMapping[] maps = batch.Maps;
  388. string file = Path.GetTempFileName ();
  389. StreamWriter sw = new StreamWriter (file);
  390. // Console.WriteLine ("Generating " + file);
  391. SerializationCodeGenerator gen = new SerializationCodeGenerator (maps);
  392. try
  393. {
  394. gen.GenerateSerializers (sw);
  395. }
  396. catch (Exception ex)
  397. {
  398. Console.WriteLine ("Serializer could not be generated");
  399. Console.WriteLine (ex);
  400. if (deleteTempFiles)
  401. File.Delete (file);
  402. return;
  403. }
  404. sw.Close ();
  405. CSharpCodeProvider provider = new CSharpCodeProvider();
  406. ICodeCompiler comp = provider.CreateCompiler ();
  407. CompilerParameters cp = new CompilerParameters();
  408. cp.GenerateExecutable = false;
  409. cp.IncludeDebugInformation = false;
  410. cp.GenerateInMemory = true;
  411. cp.ReferencedAssemblies.Add ("System.dll");
  412. cp.ReferencedAssemblies.Add ("System.Xml");
  413. foreach (Type rtype in gen.ReferencedTypes)
  414. {
  415. if (!cp.ReferencedAssemblies.Contains (rtype.Assembly.Location))
  416. cp.ReferencedAssemblies.Add (rtype.Assembly.Location);
  417. }
  418. CompilerResults res = comp.CompileAssemblyFromFile (cp, file);
  419. if (res.Errors.Count > 0)
  420. {
  421. Console.WriteLine ("Error while compiling generated serializer");
  422. foreach (CompilerError error in res.Errors)
  423. Console.WriteLine (error);
  424. if (deleteTempFiles)
  425. File.Delete (file);
  426. return;
  427. }
  428. GenerationResult[] results = gen.GenerationResults;
  429. for (int n=0; n<results.Length; n++)
  430. {
  431. GenerationResult gres = results[n];
  432. SerializerData sd = batch.Datas [n];
  433. lock (sd)
  434. {
  435. sd.WriterType = res.CompiledAssembly.GetType (gres.Namespace + "." + gres.WriterClassName);
  436. sd.ReaderType = res.CompiledAssembly.GetType (gres.Namespace + "." + gres.ReaderClassName);
  437. sd.WriterMethod = sd.WriterType.GetMethod (gres.WriteMethodName);
  438. sd.ReaderMethod = sd.ReaderType.GetMethod (gres.ReadMethodName);
  439. sd.Batch = null;
  440. }
  441. }
  442. if (deleteTempFiles)
  443. File.Delete (file);
  444. // Console.WriteLine ("Generation finished - " + (DateTime.Now - tim).TotalMilliseconds + " ms");
  445. }
  446. #endregion // Methods
  447. }
  448. }