PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.Runtime.Serialization.Internal/Microsoft/Runtime/Serialization/DataContractSet.cs

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