1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.Runtime.Serialization
7 using System.Collections.Generic;
8 using System.Reflection;
10 using System.Security.Permissions;
11 using System.Threading;
13 using System.Xml.Schema;
14 using System.Xml.Serialization;
15 using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
17 internal delegate IXmlSerializable CreateXmlSerializableDelegate();
19 public sealed class XmlDataContract : DataContract
21 internal sealed class XmlDataContract : DataContract
24 [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization."
25 + " Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
27 XmlDataContractCriticalHelper helper;
29 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
30 Safe = "Doesn't leak anything.")]
31 [SecuritySafeCritical]
32 internal XmlDataContract()
33 : base(new XmlDataContractCriticalHelper())
35 helper = base.Helper as XmlDataContractCriticalHelper;
38 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
39 Safe = "Doesn't leak anything.")]
40 [SecuritySafeCritical]
41 internal XmlDataContract(Type type)
42 : base(new XmlDataContractCriticalHelper(type))
44 helper = base.Helper as XmlDataContractCriticalHelper;
47 internal override DataContractDictionary KnownDataContracts
49 [Fx.Tag.SecurityNote(Critical = "Fetches the critical KnownDataContracts property.",
50 Safe = "KnownDataContracts only needs to be protected for write.")]
51 [SecuritySafeCritical]
52 get { return helper.KnownDataContracts; }
54 [Fx.Tag.SecurityNote(Critical = "Sets the critical KnownDataContracts property.")]
56 set { helper.KnownDataContracts = value; }
59 internal XmlSchemaType XsdType
61 [Fx.Tag.SecurityNote(Critical = "Fetches the critical XsdType property.",
62 Safe = "XsdType only needs to be protected for write.")]
63 [SecuritySafeCritical]
64 get { return helper.XsdType; }
66 [Fx.Tag.SecurityNote(Critical = "Sets the critical XsdType property.")]
68 set { helper.XsdType = value; }
71 internal bool IsAnonymous
73 [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsAnonymous property.",
74 Safe = "IsAnonymous only needs to be protected for write.")]
75 [SecuritySafeCritical]
76 get { return helper.IsAnonymous; }
79 internal override bool HasRoot
81 [Fx.Tag.SecurityNote(Critical = "Fetches the critical HasRoot property.",
82 Safe = "HasRoot only needs to be protected for write.")]
83 [SecuritySafeCritical]
84 get { return helper.HasRoot; }
86 [Fx.Tag.SecurityNote(Critical = "Sets the critical HasRoot property.")]
88 set { helper.HasRoot = value; }
91 internal override XmlDictionaryString TopLevelElementName
93 [Fx.Tag.SecurityNote(Critical = "Fetches the critical TopLevelElementName property.",
94 Safe = "TopLevelElementName only needs to be protected for write.")]
95 [SecuritySafeCritical]
96 get { return helper.TopLevelElementName; }
98 [Fx.Tag.SecurityNote(Critical = "Sets the critical TopLevelElementName property.")]
100 set { helper.TopLevelElementName = value; }
103 internal override XmlDictionaryString TopLevelElementNamespace
105 [Fx.Tag.SecurityNote(Critical = "Fetches the critical TopLevelElementNamespace property.",
106 Safe = "TopLevelElementNamespace only needs to be protected for write.")]
107 [SecuritySafeCritical]
108 get { return helper.TopLevelElementNamespace; }
110 [Fx.Tag.SecurityNote(Critical = "Sets the critical TopLevelElementNamespace property.")]
112 set { helper.TopLevelElementNamespace = value; }
115 internal bool IsTopLevelElementNullable
117 [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsTopLevelElementNullable property.",
118 Safe = "IsTopLevelElementNullable only needs to be protected for write.")]
119 [SecuritySafeCritical]
120 get { return helper.IsTopLevelElementNullable; }
122 [Fx.Tag.SecurityNote(Critical = "Sets the critical IsTopLevelElementNullable property.")]
124 set { helper.IsTopLevelElementNullable = value; }
127 internal bool IsTypeDefinedOnImport
129 [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsTypeDefinedOnImport property.",
130 Safe = "IsTypeDefinedOnImport only needs to be protected for write.")]
131 [SecuritySafeCritical]
132 get { return helper.IsTypeDefinedOnImport; }
134 [Fx.Tag.SecurityNote(Critical = "Sets the critical IsTypeDefinedOnImport property.")]
136 set { helper.IsTypeDefinedOnImport = value; }
139 internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate
141 [Fx.Tag.SecurityNote(Critical = "Fetches the critical CreateXmlSerializableDelegate property.",
142 Safe = "CreateXmlSerializableDelegate only needs to be protected for write; initialized in getter if null.")]
143 [SecuritySafeCritical]
146 if (helper.CreateXmlSerializableDelegate == null)
150 if (helper.CreateXmlSerializableDelegate == null)
152 CreateXmlSerializableDelegate tempCreateXmlSerializable = GenerateCreateXmlSerializableDelegate();
153 Thread.MemoryBarrier();
154 helper.CreateXmlSerializableDelegate = tempCreateXmlSerializable;
158 return helper.CreateXmlSerializableDelegate;
162 internal override bool CanContainReferences
164 get { return false; }
167 internal override bool IsBuiltInDataContract
171 return UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray;
175 [Fx.Tag.SecurityNote(Critical = "Holds all state used for for (de)serializing XML types."
176 + " Since the data is cached statically, we lock down access to it.")]
177 [SecurityCritical(SecurityCriticalScope.Everything)]
178 class XmlDataContractCriticalHelper : DataContract.DataContractCriticalHelper
180 DataContractDictionary knownDataContracts;
181 bool isKnownTypeAttributeChecked;
182 XmlDictionaryString topLevelElementName;
183 XmlDictionaryString topLevelElementNamespace;
184 bool isTopLevelElementNullable;
185 bool isTypeDefinedOnImport;
186 XmlSchemaType xsdType;
188 CreateXmlSerializableDelegate createXmlSerializable;
190 internal XmlDataContractCriticalHelper()
194 internal XmlDataContractCriticalHelper(Type type)
197 if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
198 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IXmlSerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type))));
199 if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
200 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IXmlSerializableCannotHaveCollectionDataContract, DataContract.GetClrTypeFullName(type))));
201 XmlSchemaType xsdType;
203 XmlQualifiedName stableName;
204 SchemaExporter.GetXmlTypeInfo(type, out stableName, out xsdType, out hasRoot);
205 this.StableName = stableName;
206 this.XsdType = xsdType;
207 this.HasRoot = hasRoot;
208 XmlDictionary dictionary = new XmlDictionary();
209 this.Name = dictionary.Add(StableName.Name);
210 this.Namespace = dictionary.Add(StableName.Namespace);
211 object[] xmlRootAttributes = (UnderlyingType == null) ? null : UnderlyingType.GetCustomAttributes(Globals.TypeOfXmlRootAttribute, false);
212 if (xmlRootAttributes == null || xmlRootAttributes.Length == 0)
216 topLevelElementName = Name;
217 topLevelElementNamespace = (this.StableName.Namespace == Globals.SchemaNamespace) ? DictionaryGlobals.EmptyString : Namespace;
218 isTopLevelElementNullable = true;
225 XmlRootAttribute xmlRootAttribute = (XmlRootAttribute)xmlRootAttributes[0];
226 isTopLevelElementNullable = xmlRootAttribute.IsNullable;
227 string elementName = xmlRootAttribute.ElementName;
228 topLevelElementName = (elementName == null || elementName.Length == 0) ? Name : dictionary.Add(DataContract.EncodeLocalName(elementName));
229 string elementNs = xmlRootAttribute.Namespace;
230 topLevelElementNamespace = (elementNs == null || elementNs.Length == 0) ? DictionaryGlobals.EmptyString : dictionary.Add(elementNs);
234 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IsAnyCannotHaveXmlRoot, DataContract.GetClrTypeFullName(UnderlyingType))));
239 internal override DataContractDictionary KnownDataContracts
243 if (!isKnownTypeAttributeChecked && UnderlyingType != null)
247 if (!isKnownTypeAttributeChecked)
249 knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType);
250 Thread.MemoryBarrier();
251 isKnownTypeAttributeChecked = true;
255 return knownDataContracts;
257 set { knownDataContracts = value; }
260 internal XmlSchemaType XsdType
262 get { return xsdType; }
263 set { xsdType = value; }
266 internal bool IsAnonymous
268 get { return xsdType != null; }
271 internal override bool HasRoot
273 get { return hasRoot; }
274 set { hasRoot = value; }
277 internal override XmlDictionaryString TopLevelElementName
279 get { return topLevelElementName; }
280 set { topLevelElementName = value; }
283 internal override XmlDictionaryString TopLevelElementNamespace
285 get { return topLevelElementNamespace; }
286 set { topLevelElementNamespace = value; }
289 internal bool IsTopLevelElementNullable
291 get { return isTopLevelElementNullable; }
292 set { isTopLevelElementNullable = value; }
295 internal bool IsTypeDefinedOnImport
297 get { return isTypeDefinedOnImport; }
298 set { isTypeDefinedOnImport = value; }
301 internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate
303 get { return createXmlSerializable; }
304 set { createXmlSerializable = value; }
309 ConstructorInfo GetConstructor()
311 Type type = UnderlyingType;
313 if (type.IsValueType)
316 ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
318 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.IXmlSerializableMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type))));
323 [Fx.Tag.SecurityNote(Critical = "Sets critical properties on XmlDataContract.")]
325 internal void SetTopLevelElementName(XmlQualifiedName elementName)
327 if (elementName != null)
329 XmlDictionary dictionary = new XmlDictionary();
330 this.TopLevelElementName = dictionary.Add(elementName.Name);
331 this.TopLevelElementNamespace = dictionary.Add(elementName.Namespace);
335 [Fx.Tag.SecurityNote(Critical = "Calls CodeGenerator.BeginMethod which is SecurityCritical.",
336 Safe = "Self-contained: returns the delegate to the generated IL but otherwise all IL generation is self-contained here.")]
337 [SecuritySafeCritical]
338 internal CreateXmlSerializableDelegate GenerateCreateXmlSerializableDelegate()
340 Type type = this.UnderlyingType;
341 CodeGenerator ilg = new CodeGenerator();
342 bool memberAccessFlag = RequiresMemberAccessForCreate(null);
345 ilg.BeginMethod("Create" + DataContract.GetClrTypeFullName(type), typeof(CreateXmlSerializableDelegate), memberAccessFlag);
347 catch (SecurityException securityException)
349 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
351 RequiresMemberAccessForCreate(securityException);
358 if (type.IsValueType)
360 System.Reflection.Emit.LocalBuilder local = ilg.DeclareLocal(type, type.Name + "Value");
367 ilg.New(GetConstructor());
369 ilg.ConvertValue(this.UnderlyingType, Globals.TypeOfIXmlSerializable);
371 return (CreateXmlSerializableDelegate)ilg.EndMethod();
374 [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Calculates whether this Xml type requires MemberAccessPermission for deserialization."
375 + " Since this information is used to determine whether to give the generated code access"
376 + " permissions to private members, any changes to the logic should be reviewed.")]
377 bool RequiresMemberAccessForCreate(SecurityException securityException)
379 if (!IsTypeVisible(UnderlyingType))
381 if (securityException != null)
383 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
384 new SecurityException(SR.GetString(SR.PartialTrustIXmlSerializableTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)),
390 if (ConstructorRequiresMemberAccess(GetConstructor()))
392 if (securityException != null)
394 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
395 new SecurityException(SR.GetString(SR.PartialTrustIXmlSerialzableNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)),
404 internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
406 if (IsEqualOrChecked(other, checkedContracts))
409 XmlDataContract dataContract = other as XmlDataContract;
410 if (dataContract != null)
412 if (this.HasRoot != dataContract.HasRoot)
415 if (this.IsAnonymous)
417 return dataContract.IsAnonymous;
421 return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace);
427 public override int GetHashCode()
429 return base.GetHashCode();
432 public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
435 XmlObjectSerializerWriteContext.WriteRootIXmlSerializable(xmlWriter, obj);
437 context.WriteIXmlSerializable(xmlWriter, obj);
440 public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
445 o = XmlObjectSerializerReadContext.ReadRootIXmlSerializable(xmlReader, this, true /*isMemberType*/);
449 o = context.ReadIXmlSerializable(xmlReader, this, true /*isMemberType*/);
450 context.AddNewObject(o);
452 xmlReader.ReadEndElement();