DataContractSet.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.Runtime.Serialization
  5. {
  6. using System;
  7. using System.Xml;
  8. using System.Xml.Schema;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.Reflection;
  12. using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
  13. using System.Text;
  14. internal class DataContractSet
  15. {
  16. Dictionary<XmlQualifiedName, DataContract> contracts;
  17. Dictionary<DataContract, object> processedContracts;
  18. IDataContractSurrogate dataContractSurrogate;
  19. Hashtable surrogateDataTable;
  20. DataContractDictionary knownTypesForObject;
  21. ICollection<Type> referencedTypes;
  22. ICollection<Type> referencedCollectionTypes;
  23. Dictionary<XmlQualifiedName, object> referencedTypesDictionary;
  24. Dictionary<XmlQualifiedName, object> referencedCollectionTypesDictionary;
  25. internal DataContractSet(IDataContractSurrogate dataContractSurrogate) : this(dataContractSurrogate, null, null) { }
  26. internal DataContractSet(IDataContractSurrogate dataContractSurrogate, ICollection<Type> referencedTypes, ICollection<Type> referencedCollectionTypes)
  27. {
  28. this.dataContractSurrogate = dataContractSurrogate;
  29. this.referencedTypes = referencedTypes;
  30. this.referencedCollectionTypes = referencedCollectionTypes;
  31. }
  32. internal DataContractSet(DataContractSet dataContractSet)
  33. {
  34. if (dataContractSet == null)
  35. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("dataContractSet"));
  36. this.dataContractSurrogate = dataContractSet.dataContractSurrogate;
  37. this.referencedTypes = dataContractSet.referencedTypes;
  38. this.referencedCollectionTypes = dataContractSet.referencedCollectionTypes;
  39. foreach (KeyValuePair<XmlQualifiedName, DataContract> pair in dataContractSet)
  40. {
  41. Add(pair.Key, pair.Value);
  42. }
  43. if (dataContractSet.processedContracts != null)
  44. {
  45. foreach (KeyValuePair<DataContract, object> pair in dataContractSet.processedContracts)
  46. {
  47. ProcessedContracts.Add(pair.Key, pair.Value);
  48. }
  49. }
  50. }
  51. Dictionary<XmlQualifiedName, DataContract> Contracts
  52. {
  53. get
  54. {
  55. if (contracts == null)
  56. {
  57. contracts = new Dictionary<XmlQualifiedName, DataContract>();
  58. }
  59. return contracts;
  60. }
  61. }
  62. Dictionary<DataContract, object> ProcessedContracts
  63. {
  64. get
  65. {
  66. if (processedContracts == null)
  67. {
  68. processedContracts = new Dictionary<DataContract, object>();
  69. }
  70. return processedContracts;
  71. }
  72. }
  73. Hashtable SurrogateDataTable
  74. {
  75. get
  76. {
  77. if (surrogateDataTable == null)
  78. surrogateDataTable = new Hashtable();
  79. return surrogateDataTable;
  80. }
  81. }
  82. internal DataContractDictionary KnownTypesForObject
  83. {
  84. get { return knownTypesForObject; }
  85. set { knownTypesForObject = value; }
  86. }
  87. internal void Add(Type type)
  88. {
  89. DataContract dataContract = GetDataContract(type);
  90. EnsureTypeNotGeneric(dataContract.UnderlyingType);
  91. Add(dataContract);
  92. }
  93. internal static void EnsureTypeNotGeneric(Type type)
  94. {
  95. if (type.ContainsGenericParameters)
  96. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GenericTypeNotExportable, type)));
  97. }
  98. void Add(DataContract dataContract)
  99. {
  100. Add(dataContract.StableName, dataContract);
  101. }
  102. public void Add(XmlQualifiedName name, DataContract dataContract)
  103. {
  104. if (dataContract.IsBuiltInDataContract)
  105. return;
  106. InternalAdd(name, dataContract);
  107. }
  108. internal void InternalAdd(XmlQualifiedName name, DataContract dataContract)
  109. {
  110. DataContract dataContractInSet = null;
  111. if (Contracts.TryGetValue(name, out dataContractInSet))
  112. {
  113. if (!dataContractInSet.Equals(dataContract))
  114. {
  115. if (dataContract.UnderlyingType == null || dataContractInSet.UnderlyingType == null)
  116. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DupContractInDataContractSet, dataContract.StableName.Name, dataContract.StableName.Namespace)));
  117. else
  118. {
  119. bool typeNamesEqual = (DataContract.GetClrTypeFullName(dataContract.UnderlyingType) == DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType));
  120. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DupTypeContractInDataContractSet, (typeNamesEqual ? dataContract.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContract.UnderlyingType)), (typeNamesEqual ? dataContractInSet.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)), dataContract.StableName.Name, dataContract.StableName.Namespace)));
  121. }
  122. }
  123. }
  124. else
  125. {
  126. Contracts.Add(name, dataContract);
  127. if (dataContract is ClassDataContract)
  128. {
  129. AddClassDataContract((ClassDataContract)dataContract);
  130. }
  131. else if (dataContract is CollectionDataContract)
  132. {
  133. AddCollectionDataContract((CollectionDataContract)dataContract);
  134. }
  135. else if (dataContract is XmlDataContract)
  136. {
  137. AddXmlDataContract((XmlDataContract)dataContract);
  138. }
  139. }
  140. }
  141. void AddClassDataContract(ClassDataContract classDataContract)
  142. {
  143. if (classDataContract.BaseContract != null)
  144. {
  145. Add(classDataContract.BaseContract.StableName, classDataContract.BaseContract);
  146. }
  147. if (!classDataContract.IsISerializable)
  148. {
  149. if (classDataContract.Members != null)
  150. {
  151. for (int i = 0; i < classDataContract.Members.Count; i++)
  152. {
  153. DataMember dataMember = classDataContract.Members[i];
  154. DataContract memberDataContract = GetMemberTypeDataContract(dataMember);
  155. if (dataContractSurrogate != null && dataMember.MemberInfo != null)
  156. {
  157. object customData = DataContractSurrogateCaller.GetCustomDataToExport(
  158. dataContractSurrogate,
  159. dataMember.MemberInfo,
  160. memberDataContract.UnderlyingType);
  161. if (customData != null)
  162. SurrogateDataTable.Add(dataMember, customData);
  163. }
  164. Add(memberDataContract.StableName, memberDataContract);
  165. }
  166. }
  167. }
  168. AddKnownDataContracts(classDataContract.KnownDataContracts);
  169. }
  170. void AddCollectionDataContract(CollectionDataContract collectionDataContract)
  171. {
  172. if (collectionDataContract.IsDictionary)
  173. {
  174. ClassDataContract keyValueContract = collectionDataContract.ItemContract as ClassDataContract;
  175. AddClassDataContract(keyValueContract);
  176. }
  177. else
  178. {
  179. DataContract itemContract = GetItemTypeDataContract(collectionDataContract);
  180. if (itemContract != null)
  181. Add(itemContract.StableName, itemContract);
  182. }
  183. AddKnownDataContracts(collectionDataContract.KnownDataContracts);
  184. }
  185. void AddXmlDataContract(XmlDataContract xmlDataContract)
  186. {
  187. AddKnownDataContracts(xmlDataContract.KnownDataContracts);
  188. }
  189. void AddKnownDataContracts(DataContractDictionary knownDataContracts)
  190. {
  191. if (knownDataContracts != null)
  192. {
  193. foreach (DataContract knownDataContract in knownDataContracts.Values)
  194. {
  195. Add(knownDataContract);
  196. }
  197. }
  198. }
  199. internal XmlQualifiedName GetStableName(Type clrType)
  200. {
  201. if (dataContractSurrogate != null)
  202. {
  203. Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, clrType);
  204. //if (clrType.IsValueType != dcType.IsValueType)
  205. // throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ValueTypeMismatchInSurrogatedType, dcType, clrType)));
  206. return DataContract.GetStableName(dcType);
  207. }
  208. return DataContract.GetStableName(clrType);
  209. }
  210. internal DataContract GetDataContract(Type clrType)
  211. {
  212. if (dataContractSurrogate == null)
  213. return DataContract.GetDataContract(clrType);
  214. DataContract dataContract = DataContract.GetBuiltInDataContract(clrType);
  215. if (dataContract != null)
  216. return dataContract;
  217. Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, clrType);
  218. //if (clrType.IsValueType != dcType.IsValueType)
  219. // throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ValueTypeMismatchInSurrogatedType, dcType, clrType)));
  220. dataContract = DataContract.GetDataContract(dcType);
  221. if (!SurrogateDataTable.Contains(dataContract))
  222. {
  223. object customData = DataContractSurrogateCaller.GetCustomDataToExport(
  224. dataContractSurrogate, clrType, dcType);
  225. if (customData != null)
  226. SurrogateDataTable.Add(dataContract, customData);
  227. }
  228. return dataContract;
  229. }
  230. internal DataContract GetMemberTypeDataContract(DataMember dataMember)
  231. {
  232. if (dataMember.MemberInfo != null)
  233. {
  234. Type dataMemberType = dataMember.MemberType;
  235. if (dataMember.IsGetOnlyCollection)
  236. {
  237. if (dataContractSurrogate != null)
  238. {
  239. Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, dataMemberType);
  240. if (dcType != dataMemberType)
  241. {
  242. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.SurrogatesWithGetOnlyCollectionsNotSupported,
  243. DataContract.GetClrTypeFullName(dataMemberType), DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType), dataMember.MemberInfo.Name)));
  244. }
  245. }
  246. return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType, SerializationMode.SharedContract);
  247. }
  248. else
  249. {
  250. return GetDataContract(dataMemberType);
  251. }
  252. }
  253. return dataMember.MemberTypeContract;
  254. }
  255. internal DataContract GetItemTypeDataContract(CollectionDataContract collectionContract)
  256. {
  257. if (collectionContract.ItemType != null)
  258. return GetDataContract(collectionContract.ItemType);
  259. return collectionContract.ItemContract;
  260. }
  261. internal object GetSurrogateData(object key)
  262. {
  263. return SurrogateDataTable[key];
  264. }
  265. internal void SetSurrogateData(object key, object surrogateData)
  266. {
  267. SurrogateDataTable[key] = surrogateData;
  268. }
  269. public DataContract this[XmlQualifiedName key]
  270. {
  271. get
  272. {
  273. DataContract dataContract = DataContract.GetBuiltInDataContract(key.Name, key.Namespace);
  274. if (dataContract == null)
  275. {
  276. Contracts.TryGetValue(key, out dataContract);
  277. }
  278. return dataContract;
  279. }
  280. }
  281. public IDataContractSurrogate DataContractSurrogate
  282. {
  283. get { return dataContractSurrogate; }
  284. }
  285. public bool Remove(XmlQualifiedName key)
  286. {
  287. if (DataContract.GetBuiltInDataContract(key.Name, key.Namespace) != null)
  288. return false;
  289. return Contracts.Remove(key);
  290. }
  291. public IEnumerator<KeyValuePair<XmlQualifiedName, DataContract>> GetEnumerator()
  292. {
  293. return Contracts.GetEnumerator();
  294. }
  295. internal bool IsContractProcessed(DataContract dataContract)
  296. {
  297. return ProcessedContracts.ContainsKey(dataContract);
  298. }
  299. internal void SetContractProcessed(DataContract dataContract)
  300. {
  301. ProcessedContracts.Add(dataContract, dataContract);
  302. }
  303. #if !NO_CODEDOM
  304. internal ContractCodeDomInfo GetContractCodeDomInfo(DataContract dataContract)
  305. {
  306. object info;
  307. if (ProcessedContracts.TryGetValue(dataContract, out info))
  308. return (ContractCodeDomInfo)info;
  309. return null;
  310. }
  311. internal void SetContractCodeDomInfo(DataContract dataContract, ContractCodeDomInfo info)
  312. {
  313. ProcessedContracts.Add(dataContract, info);
  314. }
  315. #endif
  316. Dictionary<XmlQualifiedName, object> GetReferencedTypes()
  317. {
  318. if (referencedTypesDictionary == null)
  319. {
  320. referencedTypesDictionary = new Dictionary<XmlQualifiedName, object>();
  321. //Always include Nullable as referenced type
  322. //Do not allow surrogating Nullable<T>
  323. referencedTypesDictionary.Add(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable);
  324. if (this.referencedTypes != null)
  325. {
  326. foreach (Type type in this.referencedTypes)
  327. {
  328. if (type == null)
  329. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ReferencedTypesCannotContainNull)));
  330. AddReferencedType(referencedTypesDictionary, type);
  331. }
  332. }
  333. }
  334. return referencedTypesDictionary;
  335. }
  336. Dictionary<XmlQualifiedName, object> GetReferencedCollectionTypes()
  337. {
  338. if (referencedCollectionTypesDictionary == null)
  339. {
  340. referencedCollectionTypesDictionary = new Dictionary<XmlQualifiedName, object>();
  341. if (this.referencedCollectionTypes != null)
  342. {
  343. foreach (Type type in this.referencedCollectionTypes)
  344. {
  345. if (type == null)
  346. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ReferencedCollectionTypesCannotContainNull)));
  347. AddReferencedType(referencedCollectionTypesDictionary, type);
  348. }
  349. }
  350. XmlQualifiedName genericDictionaryName = DataContract.GetStableName(Globals.TypeOfDictionaryGeneric);
  351. if (!referencedCollectionTypesDictionary.ContainsKey(genericDictionaryName) && GetReferencedTypes().ContainsKey(genericDictionaryName))
  352. AddReferencedType(referencedCollectionTypesDictionary, Globals.TypeOfDictionaryGeneric);
  353. }
  354. return referencedCollectionTypesDictionary;
  355. }
  356. void AddReferencedType(Dictionary<XmlQualifiedName, object> referencedTypes, Type type)
  357. {
  358. if (IsTypeReferenceable(type))
  359. {
  360. XmlQualifiedName stableName;
  361. try
  362. {
  363. stableName = this.GetStableName(type);
  364. }
  365. catch (InvalidDataContractException)
  366. {
  367. // Type not referenceable if we can't get a stable name.
  368. return;
  369. }
  370. catch (InvalidOperationException)
  371. {
  372. // Type not referenceable if we can't get a stable name.
  373. return;
  374. }
  375. object value;
  376. if (referencedTypes.TryGetValue(stableName, out value))
  377. {
  378. Type referencedType = value as Type;
  379. if (referencedType != null)
  380. {
  381. if (referencedType != type)
  382. {
  383. referencedTypes.Remove(stableName);
  384. List<Type> types = new List<Type>();
  385. types.Add(referencedType);
  386. types.Add(type);
  387. referencedTypes.Add(stableName, types);
  388. }
  389. }
  390. else
  391. {
  392. List<Type> types = (List<Type>)value;
  393. if (!types.Contains(type))
  394. types.Add(type);
  395. }
  396. }
  397. else
  398. referencedTypes.Add(stableName, type);
  399. }
  400. }
  401. internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, out Type type)
  402. {
  403. return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type);
  404. }
  405. internal bool TryGetReferencedCollectionType(XmlQualifiedName stableName, DataContract dataContract, out Type type)
  406. {
  407. return TryGetReferencedType(stableName, dataContract, true/*useReferencedCollectionTypes*/, out type);
  408. }
  409. bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, bool useReferencedCollectionTypes, out Type type)
  410. {
  411. object value;
  412. Dictionary<XmlQualifiedName, object> referencedTypes = useReferencedCollectionTypes ? GetReferencedCollectionTypes() : GetReferencedTypes();
  413. if (referencedTypes.TryGetValue(stableName, out value))
  414. {
  415. type = value as Type;
  416. if (type != null)
  417. return true;
  418. else
  419. {
  420. // Throw ambiguous type match exception
  421. List<Type> types = (List<Type>)value;
  422. StringBuilder errorMessage = new StringBuilder();
  423. bool containsGenericType = false;
  424. for (int i = 0; i < types.Count; i++)
  425. {
  426. Type conflictingType = types[i];
  427. if (!containsGenericType)
  428. containsGenericType = conflictingType.IsGenericTypeDefinition;
  429. errorMessage.AppendFormat("{0}\"{1}\" ", Environment.NewLine, conflictingType.AssemblyQualifiedName);
  430. if (dataContract != null)
  431. {
  432. DataContract other = this.GetDataContract(conflictingType);
  433. errorMessage.Append(SR.GetString(((other != null && other.Equals(dataContract)) ? SR.ReferencedTypeMatchingMessage : SR.ReferencedTypeNotMatchingMessage)));
  434. }
  435. }
  436. if (containsGenericType)
  437. {
  438. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
  439. (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes1 : SR.AmbiguousReferencedTypes1),
  440. errorMessage.ToString())));
  441. }
  442. else
  443. {
  444. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
  445. (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes3 : SR.AmbiguousReferencedTypes3),
  446. XmlConvert.DecodeName(stableName.Name),
  447. stableName.Namespace,
  448. errorMessage.ToString())));
  449. }
  450. }
  451. }
  452. type = null;
  453. return false;
  454. }
  455. static bool IsTypeReferenceable(Type type)
  456. {
  457. Type itemType;
  458. try
  459. {
  460. return (type.IsSerializable ||
  461. type.IsDefined(Globals.TypeOfDataContractAttribute, false) ||
  462. (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) && !type.IsGenericTypeDefinition) ||
  463. CollectionDataContract.IsCollection(type, out itemType) ||
  464. ClassDataContract.IsNonAttributedTypeValidForSerialization(type));
  465. }
  466. catch (Exception ex)
  467. {
  468. // An exception can be thrown in the designer when a project has a runtime binding redirection for a referenced assembly or a reference dependent assembly.
  469. // Type.IsDefined is known to throw System.IO.FileLoadException.
  470. // ClassDataContract.IsNonAttributedTypeValidForSerialization is known to throw System.IO.FileNotFoundException.
  471. // We guard against all non-critical exceptions.
  472. if (Fx.IsFatal(ex))
  473. {
  474. throw;
  475. }
  476. }
  477. return false;
  478. }
  479. }
  480. }