Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / Serialization / System / Runtime / Serialization / ClassDataContract.cs / 1305376 / ClassDataContract.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Runtime.Serialization { using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Security; using System.Threading; using System.Xml; using DataContractDictionary = System.Collections.Generic.Dictionary; #if USE_REFEMIT public sealed class ClassDataContract : DataContract #else internal sealed class ClassDataContract : DataContract #endif { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members." + "statically cached and used from IL generated code. should ideally be Critical." + "marked SecurityNode to be callable from transparent IL generated code." + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")] public XmlDictionaryString[] ContractNamespaces; [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - XmlDictionaryString(s) representing the XML element names for class members." + "statically cached and used from IL generated code. should ideally be Critical." + "marked SecurityNode to be callable from transparent IL generated code." + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")] public XmlDictionaryString[] MemberNames; [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members." + "statically cached and used from IL generated code. should ideally be Critical." + "marked SecurityNode to be callable from transparent IL generated code." + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")] public XmlDictionaryString[] MemberNamespaces; [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML namespaces for members of class." + "Statically cached and used from IL generated code.")] [SecurityCritical] XmlDictionaryString[] childElementNamespaces; [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization. " + "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")] [SecurityCritical] ClassDataContractCriticalHelper helper; [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] internal ClassDataContract() : base(new ClassDataContractCriticalHelper()) { InitClassDataContract(); } [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] internal ClassDataContract(Type type) : base(new ClassDataContractCriticalHelper(type)) { InitClassDataContract(); } [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] ClassDataContract(Type type, XmlDictionaryString ns, string[] memberNames) : base(new ClassDataContractCriticalHelper(type, ns, memberNames)) { InitClassDataContract(); } [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")] [SecurityCritical] void InitClassDataContract() { this.helper = base.Helper as ClassDataContractCriticalHelper; this.ContractNamespaces = helper.ContractNamespaces; this.MemberNames = helper.MemberNames; this.MemberNamespaces = helper.MemberNamespaces; } internal ClassDataContract BaseContract { [Fx.Tag.SecurityNote(Critical = "Fetches the critical baseContract property.", Safe = "baseContract only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.BaseContract; } [Fx.Tag.SecurityNote(Critical = "Sets the critical baseContract property.")] [SecurityCritical] set { helper.BaseContract = value; } } internal List Members { [Fx.Tag.SecurityNote(Critical = "Fetches the critical members property.", Safe = "members only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.Members; } [Fx.Tag.SecurityNote(Critical = "Sets the critical members property.", Safe = "Protected for write if contract has underlyingType.")] [SecurityCritical] set { helper.Members = value; } } public XmlDictionaryString[] ChildElementNamespaces { [Fx.Tag.SecurityNote(Critical = "Sets the critical childElementNamespaces property.", Safe = "childElementNamespaces only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (this.childElementNamespaces == null) { lock (this) { if (this.childElementNamespaces == null) { if (helper.ChildElementNamespaces == null) { XmlDictionaryString[] tempChildElementamespaces = CreateChildElementNamespaces(); Thread.MemoryBarrier(); helper.ChildElementNamespaces = tempChildElementamespaces; } this.childElementNamespaces = helper.ChildElementNamespaces; } } } return this.childElementNamespaces; } } internal MethodInfo OnSerializing { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onSerializing property.", Safe = "onSerializing only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnSerializing; } } internal MethodInfo OnSerialized { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onSerialized property.", Safe = "onSerialized only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnSerialized; } } internal MethodInfo OnDeserializing { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onDeserializing property.", Safe = "onDeserializing only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnDeserializing; } } internal MethodInfo OnDeserialized { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onDeserialized property.", Safe = "onDeserialized only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnDeserialized; } } internal MethodInfo ExtensionDataSetMethod { [Fx.Tag.SecurityNote(Critical = "Fetches the critical extensionDataSetMethod property.", Safe = "extensionDataSetMethod only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.ExtensionDataSetMethod; } } internal override DataContractDictionary KnownDataContracts { [Fx.Tag.SecurityNote(Critical = "Fetches the critical knownDataContracts property.", Safe = "knownDataContracts only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.KnownDataContracts; } [Fx.Tag.SecurityNote(Critical = "Sets the critical knownDataContracts property.", Safe = "Protected for write if contract has underlyingType.")] [SecurityCritical] set { helper.KnownDataContracts = value; } } internal override bool IsISerializable { [Fx.Tag.SecurityNote(Critical = "Fetches the critical isISerializable property.", Safe = "isISerializable only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.IsISerializable; } [Fx.Tag.SecurityNote(Critical = "Sets the critical isISerializable property.", Safe = "Protected for write if contract has underlyingType.")] [SecurityCritical] set { helper.IsISerializable = value; } } internal bool IsNonAttributedType { [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsNonAttributedType property.", Safe = "IsNonAttributedType only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.IsNonAttributedType; } } internal bool HasDataContract { [Fx.Tag.SecurityNote(Critical = "Fetches the critical hasDataContract property.", Safe = "hasDataContract only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.HasDataContract; } } internal bool HasExtensionData { [Fx.Tag.SecurityNote(Critical = "Fetches the critical hasExtensionData property.", Safe = "hasExtensionData only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.HasExtensionData; } } [Fx.Tag.SecurityNote(Critical = "Fetches information about which constructor should be used to initialize ISerializable types.", Safe = "only needs to be protected for write.")] [SecuritySafeCritical] internal ConstructorInfo GetISerializableConstructor() { return helper.GetISerializableConstructor(); } [Fx.Tag.SecurityNote(Critical = "Fetches information about which constructor should be used to initialize non-attributed types that are valid for serialization.", Safe = "only needs to be protected for write.")] [SecuritySafeCritical] internal ConstructorInfo GetNonAttributedTypeConstructor() { return helper.GetNonAttributedTypeConstructor(); } internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate { [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatWriterDelegate property.", Safe = "xmlFormatWriterDelegate only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (helper.XmlFormatWriterDelegate == null) { lock (this) { if (helper.XmlFormatWriterDelegate == null) { XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this); Thread.MemoryBarrier(); helper.XmlFormatWriterDelegate = tempDelegate; } } } return helper.XmlFormatWriterDelegate; } } internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatReaderDelegate property.", Safe = "xmlFormatReaderDelegate only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (helper.XmlFormatReaderDelegate == null) { lock (this) { if (helper.XmlFormatReaderDelegate == null) { XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this); Thread.MemoryBarrier(); helper.XmlFormatReaderDelegate = tempDelegate; } } } return helper.XmlFormatReaderDelegate; } } internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames) { return new ClassDataContract(type, ns, memberNames); } internal static void CheckAndAddMember(List members, DataMember memberContract, Dictionary memberNamesTable) { DataMember existingMemberContract; if (memberNamesTable.TryGetValue(memberContract.Name, out existingMemberContract)) { Type declaringType = memberContract.MemberInfo.DeclaringType; DataContract.ThrowInvalidDataContractException( SR.GetString((declaringType.IsEnum ? SR.DupEnumMemberValue : SR.DupMemberName), existingMemberContract.MemberInfo.Name, memberContract.MemberInfo.Name, DataContract.GetClrTypeFullName(declaringType), memberContract.Name), declaringType); } memberNamesTable.Add(memberContract.Name, memberContract); members.Add(memberContract); } internal static XmlDictionaryString GetChildNamespaceToDeclare(DataContract dataContract, Type childType, XmlDictionary dictionary) { childType = DataContract.UnwrapNullableType(childType); if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType) && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull) { string ns = DataContract.GetStableName(childType).Namespace; if (ns.Length > 0 && ns != dataContract.Namespace.Value) return dictionary.Add(ns); } return null; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision." + "isNonAttributedType must be calculated correctly." + "IsNonAttributedTypeValidForSerialization is used as part of the isNonAttributedType calculation and is therefore marked with SecurityNote.", Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value.")] // check whether a corresponding update is required in DataContractCriticalHelper.CreateDataContract static internal bool IsNonAttributedTypeValidForSerialization(Type type) { if (type.IsArray) return false; if (type.IsEnum) return false; if (type.IsGenericParameter) return false; if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) return false; if (type.IsPointer) return false; if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) return false; Type[] interfaceTypes = type.GetInterfaces(); foreach (Type interfaceType in interfaceTypes) { if (CollectionDataContract.IsCollectionInterface(interfaceType)) return false; } if (type.IsSerializable) return false; if (Globals.TypeOfISerializable.IsAssignableFrom(type)) return false; if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) return false; if (type == Globals.TypeOfExtensionDataObject) return false; if (type.IsValueType) { return type.IsVisible; } else { return (type.IsVisible && type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null) != null); } } XmlDictionaryString[] CreateChildElementNamespaces() { if (Members == null) return null; XmlDictionaryString[] baseChildElementNamespaces = null; if (this.BaseContract != null) baseChildElementNamespaces = this.BaseContract.ChildElementNamespaces; int baseChildElementNamespaceCount = (baseChildElementNamespaces != null) ? baseChildElementNamespaces.Length : 0; XmlDictionaryString[] childElementNamespaces = new XmlDictionaryString[Members.Count + baseChildElementNamespaceCount]; if (baseChildElementNamespaceCount > 0) Array.Copy(baseChildElementNamespaces, 0, childElementNamespaces, 0, baseChildElementNamespaces.Length); XmlDictionary dictionary = new XmlDictionary(); for (int i = 0; i < this.Members.Count; i++) { childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, this.Members[i].MemberType, dictionary); } return childElementNamespaces; } [Fx.Tag.SecurityNote(Critical = "Calls critical method on helper.", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] void EnsureMethodsImported() { helper.EnsureMethodsImported(); } public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) { XmlFormatWriterDelegate(xmlWriter, obj, context, this); } public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) { xmlReader.Read(); object o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces); xmlReader.ReadEndElement(); return o; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for deserialization." + "Since this information is used to determine whether to give the generated code access " + "permissions to private members, any changes to the logic should be reviewed.")] internal bool RequiresMemberAccessForRead(SecurityException securityException) { EnsureMethodsImported(); if (!IsTypeVisible(UnderlyingType)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException)) return true; if (ConstructorRequiresMemberAccess(GetISerializableConstructor())) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustISerializableNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor())) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustNonAttributedSerializableTypeNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (MethodRequiresMemberAccess(this.OnDeserializing)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnDeserializingNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.OnDeserializing.Name), securityException)); } return true; } if (MethodRequiresMemberAccess(this.OnDeserialized)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnDeserializedNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.OnDeserialized.Name), securityException)); } return true; } if (this.Members != null) { for (int i = 0; i < this.Members.Count; i++) { if (this.Members[i].RequiresMemberAccessForSet()) { if (securityException != null) { if (this.Members[i].MemberInfo is FieldInfo) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractFieldSetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractPropertySetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } } return true; } } } return false; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for serialization." + " Since this information is used to determine whether to give the generated code access" + " permissions to private members, any changes to the logic should be reviewed.")] internal bool RequiresMemberAccessForWrite(SecurityException securityException) { EnsureMethodsImported(); if (!IsTypeVisible(UnderlyingType)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForWrite(securityException)) return true; if (MethodRequiresMemberAccess(this.OnSerializing)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnSerializingNotPublic, DataContract.GetClrTypeFullName(this.UnderlyingType), this.OnSerializing.Name), securityException)); } return true; } if (MethodRequiresMemberAccess(this.OnSerialized)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnSerializedNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.OnSerialized.Name), securityException)); } return true; } if (this.Members != null) { for (int i = 0; i < this.Members.Count; i++) { if (this.Members[i].RequiresMemberAccessForGet()) { if (securityException != null) { if (this.Members[i].MemberInfo is FieldInfo) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractFieldGetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractPropertyGetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } } return true; } } } return false; } [Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing classes." + " Since the data is cached statically, we lock down access to it.")] [SecurityCritical(SecurityCriticalScope.Everything)] class ClassDataContractCriticalHelper : DataContract.DataContractCriticalHelper { ClassDataContract baseContract; List members; MethodInfo onSerializing, onSerialized; MethodInfo onDeserializing, onDeserialized; MethodInfo extensionDataSetMethod; DataContractDictionary knownDataContracts; bool isISerializable; bool isKnownTypeAttributeChecked; bool isMethodChecked; bool hasExtensionData; [Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and hasDataContract.")] bool isNonAttributedType; [Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and isNonAttributedType.")] bool hasDataContract; XmlDictionaryString[] childElementNamespaces; XmlFormatClassReaderDelegate xmlFormatReaderDelegate; XmlFormatClassWriterDelegate xmlFormatWriterDelegate; public XmlDictionaryString[] ContractNamespaces; public XmlDictionaryString[] MemberNames; public XmlDictionaryString[] MemberNamespaces; internal ClassDataContractCriticalHelper() : base() { } internal ClassDataContractCriticalHelper(Type type) : base(type) { XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type); if (type == Globals.TypeOfDBNull) { this.StableName = stableName; this.members = new List (); XmlDictionary dictionary = new XmlDictionary(2); this.Name = dictionary.Add(StableName.Name); this.Namespace = dictionary.Add(StableName.Namespace); this.ContractNamespaces = this.MemberNames = this.MemberNamespaces = new XmlDictionaryString[] { }; EnsureMethodsImported(); return; } Type baseType = type.BaseType; this.isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type)); SetIsNonAttributedType(type); if (this.isISerializable) { if (HasDataContract) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ISerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type)))); if (baseType != null && !(baseType.IsSerializable && Globals.TypeOfISerializable.IsAssignableFrom(baseType))) baseType = null; } this.IsValueType = type.IsValueType; if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) { DataContract baseContract = DataContract.GetDataContract(baseType); if (baseContract is CollectionDataContract) this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract; else this.BaseContract = baseContract as ClassDataContract; if (this.BaseContract != null && this.BaseContract.IsNonAttributedType && !this.isNonAttributedType) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError (new InvalidDataContractException(SR.GetString(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes, DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(baseType)))); } } else this.BaseContract = null; hasExtensionData = (Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(type)); if (hasExtensionData && !HasDataContract && !IsNonAttributedType) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.OnlyDataContractTypesCanHaveExtensionData, DataContract.GetClrTypeFullName(type)))); if (this.isISerializable) SetDataContractName(stableName); else { this.StableName = stableName; ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); Name = dictionary.Add(StableName.Name); Namespace = dictionary.Add(StableName.Namespace); int baseMemberCount = 0; int baseContractCount = 0; if (BaseContract == null) { MemberNames = new XmlDictionaryString[Members.Count]; MemberNamespaces = new XmlDictionaryString[Members.Count]; ContractNamespaces = new XmlDictionaryString[1]; } else { baseMemberCount = BaseContract.MemberNames.Length; MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount]; Array.Copy(BaseContract.MemberNames, MemberNames, baseMemberCount); MemberNamespaces = new XmlDictionaryString[Members.Count + baseMemberCount]; Array.Copy(BaseContract.MemberNamespaces, MemberNamespaces, baseMemberCount); baseContractCount = BaseContract.ContractNamespaces.Length; ContractNamespaces = new XmlDictionaryString[1 + baseContractCount]; Array.Copy(BaseContract.ContractNamespaces, ContractNamespaces, baseContractCount); } ContractNamespaces[baseContractCount] = Namespace; for (int i = 0; i < Members.Count; i++) { MemberNames[i + baseMemberCount] = dictionary.Add(Members[i].Name); MemberNamespaces[i + baseMemberCount] = Namespace; } } EnsureMethodsImported(); } internal ClassDataContractCriticalHelper(Type type, XmlDictionaryString ns, string[] memberNames) : base(type) { this.StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value); ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(1 + Members.Count); Name = dictionary.Add(StableName.Name); Namespace = ns; ContractNamespaces = new XmlDictionaryString[] { Namespace }; MemberNames = new XmlDictionaryString[Members.Count]; MemberNamespaces = new XmlDictionaryString[Members.Count]; for (int i = 0; i < Members.Count; i++) { Members[i].Name = memberNames[i]; MemberNames[i] = dictionary.Add(Members[i].Name); MemberNamespaces[i] = Namespace; } EnsureMethodsImported(); } void EnsureIsReferenceImported(Type type) { DataContractAttribute dataContractAttribute; bool isReference = false; bool hasDataContractAttribute = TryGetDCAttribute(type, out dataContractAttribute); if (BaseContract != null) { if (hasDataContractAttribute && dataContractAttribute.IsReferenceSetExplicit) { bool baseIsReference = this.BaseContract.IsReference; if ((baseIsReference && !dataContractAttribute.IsReference) || (!baseIsReference && dataContractAttribute.IsReference)) { DataContract.ThrowInvalidDataContractException( SR.GetString(SR.InconsistentIsReference, DataContract.GetClrTypeFullName(type), dataContractAttribute.IsReference, DataContract.GetClrTypeFullName(this.BaseContract.UnderlyingType), this.BaseContract.IsReference), type); } else { isReference = dataContractAttribute.IsReference; } } else { isReference = this.BaseContract.IsReference; } } else if (hasDataContractAttribute) { if (dataContractAttribute.IsReference) isReference = dataContractAttribute.IsReference; } if (isReference && type.IsValueType) { DataContract.ThrowInvalidDataContractException( SR.GetString(SR.ValueTypeCannotHaveIsReference, DataContract.GetClrTypeFullName(type), true, false), type); return; } this.IsReference = isReference; } void ImportDataMembers() { Type type = this.UnderlyingType; EnsureIsReferenceImported(type); List tempMembers = new List (); Dictionary memberNamesTable = new Dictionary (); MemberInfo[] memberInfos; if (this.isNonAttributedType) { memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); } else { memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } for (int i = 0; i < memberInfos.Length; i++) { MemberInfo member = memberInfos[i]; if (HasDataContract) { object[] memberAttributes = member.GetCustomAttributes(typeof(DataMemberAttribute), false); if (memberAttributes != null && memberAttributes.Length > 0) { if (memberAttributes.Length > 1) ThrowInvalidDataContractException(SR.GetString(SR.TooManyDataMembers, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name)); DataMember memberContract = new DataMember(member); if (member.MemberType == MemberTypes.Property) { PropertyInfo property = (PropertyInfo)member; MethodInfo getMethod = property.GetGetMethod(true); if (getMethod != null && IsMethodOverriding(getMethod)) continue; MethodInfo setMethod = property.GetSetMethod(true); if (setMethod != null && IsMethodOverriding(setMethod)) continue; if (getMethod == null) ThrowInvalidDataContractException(SR.GetString(SR.NoGetMethodForProperty, property.DeclaringType, property.Name)); if (setMethod == null) { if (!SetIfGetOnlyCollection(memberContract)) { ThrowInvalidDataContractException(SR.GetString(SR.NoSetMethodForProperty, property.DeclaringType, property.Name)); } } if (getMethod.GetParameters().Length > 0) ThrowInvalidDataContractException(SR.GetString(SR.IndexedPropertyCannotBeSerialized, property.DeclaringType, property.Name)); } else if (member.MemberType != MemberTypes.Field) ThrowInvalidDataContractException(SR.GetString(SR.InvalidMember, DataContract.GetClrTypeFullName(type), member.Name)); DataMemberAttribute memberAttribute = (DataMemberAttribute)memberAttributes[0]; if (memberAttribute.IsNameSetExplicit) { if (memberAttribute.Name == null || memberAttribute.Name.Length == 0) ThrowInvalidDataContractException(SR.GetString(SR.InvalidDataMemberName, member.Name, DataContract.GetClrTypeFullName(type))); memberContract.Name = memberAttribute.Name; } else memberContract.Name = member.Name; memberContract.Name = DataContract.EncodeLocalName(memberContract.Name); memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); memberContract.IsRequired = memberAttribute.IsRequired; if (memberAttribute.IsRequired && this.IsReference) { ThrowInvalidDataContractException( SR.GetString(SR.IsRequiredDataMemberOnIsReferenceDataContractType, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name, true), type); } memberContract.EmitDefaultValue = memberAttribute.EmitDefaultValue; memberContract.Order = memberAttribute.Order; CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } } else if (this.isNonAttributedType) { FieldInfo field = member as FieldInfo; PropertyInfo property = member as PropertyInfo; if ((field == null && property == null) || (field != null && field.IsInitOnly)) continue; object[] memberAttributes = member.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false); if (memberAttributes != null && memberAttributes.Length > 0) { if (memberAttributes.Length > 1) ThrowInvalidDataContractException(SR.GetString(SR.TooManyIgnoreDataMemberAttributes, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name)); else continue; } DataMember memberContract = new DataMember(member); if (property != null) { MethodInfo getMethod = property.GetGetMethod(); if (getMethod == null || IsMethodOverriding(getMethod) || getMethod.GetParameters().Length > 0) continue; MethodInfo setMethod = property.GetSetMethod(true); if (setMethod == null) { if (!SetIfGetOnlyCollection(memberContract)) continue; } else { if (!setMethod.IsPublic || IsMethodOverriding(setMethod)) continue; } //skip ExtensionData member of type ExtensionDataObject if IExtensibleDataObject is implemented in non-attributed type if (this.hasExtensionData && memberContract.MemberType == Globals.TypeOfExtensionDataObject && member.Name == Globals.ExtensionDataObjectPropertyName) continue; } memberContract.Name = DataContract.EncodeLocalName(member.Name); memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } else { FieldInfo field = member as FieldInfo; if (field != null && !field.IsNotSerialized) { DataMember memberContract = new DataMember(member); memberContract.Name = DataContract.EncodeLocalName(member.Name); object[] optionalFields = field.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false); if (optionalFields == null || optionalFields.Length == 0) { if (this.IsReference) { ThrowInvalidDataContractException( SR.GetString(SR.NonOptionalFieldMemberOnIsReferenceSerializableType, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name, true), type); } memberContract.IsRequired = true; } memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } } } if (tempMembers.Count > 1) tempMembers.Sort(DataMemberComparer.Singleton); SetIfMembersHaveConflict(tempMembers); Thread.MemoryBarrier(); members = tempMembers; } bool SetIfGetOnlyCollection(DataMember memberContract) { //OK to call IsCollection here since the use of surrogated collection types is not supported in get-only scenarios if (CollectionDataContract.IsCollection(memberContract.MemberType, false /*isConstructorRequired*/) && !memberContract.MemberType.IsValueType) { memberContract.IsGetOnlyCollection = true; return true; } return false; } void SetIfMembersHaveConflict(List members) { if (BaseContract == null) return; int baseTypeIndex = 0; List membersInHierarchy = new List (); foreach (DataMember member in members) { membersInHierarchy.Add(new Member(member, this.StableName.Namespace, baseTypeIndex)); } ClassDataContract currContract = BaseContract; while (currContract != null) { baseTypeIndex++; foreach (DataMember member in currContract.Members) { membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex)); } currContract = currContract.BaseContract; } IComparer comparer = DataMemberConflictComparer.Singleton; membersInHierarchy.Sort(comparer); for (int i = 0; i < membersInHierarchy.Count - 1; i++) { int startIndex = i; int endIndex = i; bool hasConflictingType = false; while (endIndex < membersInHierarchy.Count - 1 && String.CompareOrdinal(membersInHierarchy[endIndex].member.Name, membersInHierarchy[endIndex + 1].member.Name) == 0 && String.CompareOrdinal(membersInHierarchy[endIndex].ns, membersInHierarchy[endIndex + 1].ns) == 0) { membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member; if (!hasConflictingType) { if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType) { hasConflictingType = true; } else { hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType); } } endIndex++; } if (hasConflictingType) { for (int j = startIndex; j <= endIndex; j++) { membersInHierarchy[j].member.HasConflictingNameAndType = true; } } i = endIndex + 1; } } [Fx.Tag.SecurityNote(Critical = "Sets the critical hasDataContract field.", Safe = "Uses a trusted critical API (DataContract.GetStableName) to calculate the value, does not accept the value from the caller.")] [SecuritySafeCritical] XmlQualifiedName GetStableNameAndSetHasDataContract(Type type) { return DataContract.GetStableName(type, out this.hasDataContract); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision." + "isNonAttributedType must be calculated correctly." + "SetIsNonAttributedType should not be called before GetStableNameAndSetHasDataContract since it is dependent on the correct calculation of hasDataContract.", Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value.")] void SetIsNonAttributedType(Type type) { this.isNonAttributedType = !type.IsSerializable && !this.hasDataContract && IsNonAttributedTypeValidForSerialization(type); } static bool IsMethodOverriding(MethodInfo method) { return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0); } internal void EnsureMethodsImported() { if (!isMethodChecked && UnderlyingType != null) { lock (this) { if (!isMethodChecked) { Type type = this.UnderlyingType; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); for (int i=0;i Members { get { return members; } set { members = value; } } internal MethodInfo OnSerializing { get { EnsureMethodsImported(); return onSerializing; } } internal MethodInfo OnSerialized { get { EnsureMethodsImported(); return onSerialized; } } internal MethodInfo OnDeserializing { get { EnsureMethodsImported(); return onDeserializing; } } internal MethodInfo OnDeserialized { get { EnsureMethodsImported(); return onDeserialized; } } internal MethodInfo ExtensionDataSetMethod { get { EnsureMethodsImported(); return extensionDataSetMethod; } } internal override DataContractDictionary KnownDataContracts { get { if (!isKnownTypeAttributeChecked && UnderlyingType != null) { lock (this) { if (!isKnownTypeAttributeChecked) { knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType); Thread.MemoryBarrier(); isKnownTypeAttributeChecked = true; } } } return knownDataContracts; } set { knownDataContracts = value; } } internal override bool IsISerializable { get { return isISerializable; } set { isISerializable = value; } } internal bool HasDataContract { get { return hasDataContract; } } internal bool HasExtensionData { get { return hasExtensionData; } } internal bool IsNonAttributedType { get { return isNonAttributedType; } } internal ConstructorInfo GetISerializableConstructor() { if (!IsISerializable) return null; ConstructorInfo ctor = UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, SerInfoCtorArgs, null); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(UnderlyingType)))); return ctor; } internal ConstructorInfo GetNonAttributedTypeConstructor() { if (!this.IsNonAttributedType) return null; Type type = UnderlyingType; if (type.IsValueType) return null; ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); return ctor; } internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate { get { return xmlFormatWriterDelegate; } set { xmlFormatWriterDelegate = value; } } internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { get { return xmlFormatReaderDelegate; } set { xmlFormatReaderDelegate = value; } } public XmlDictionaryString[] ChildElementNamespaces { get { return childElementNamespaces; } set { childElementNamespaces = value; } } static Type[] serInfoCtorArgs; static Type[] SerInfoCtorArgs { get { if (serInfoCtorArgs == null) serInfoCtorArgs = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; return serInfoCtorArgs; } } internal struct Member { internal Member(DataMember member, string ns, int baseTypeIndex) { this.member = member; this.ns = ns; this.baseTypeIndex = baseTypeIndex; } internal DataMember member; internal string ns; internal int baseTypeIndex; } internal class DataMemberConflictComparer : IComparer { public int Compare(Member x, Member y) { int nsCompare = String.CompareOrdinal(x.ns, y.ns); if (nsCompare != 0) return nsCompare; int nameCompare = String.CompareOrdinal(x.member.Name, y.member.Name); if (nameCompare != 0) return nameCompare; return x.baseTypeIndex - y.baseTypeIndex; } internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer(); } } [Fx.Tag.SecurityNote(Critical = "Sets critical properties on ClassDataContract .", Safe = "Called during schema import/code generation.")] [SecuritySafeCritical] internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { Type type = UnderlyingType; if(!type.IsGenericType || !type.ContainsGenericParameters) return this; lock(this) { DataContract boundContract; if(boundContracts.TryGetValue(this, out boundContract)) return boundContract; ClassDataContract boundClassContract = new ClassDataContract(); boundContracts.Add(this, boundClassContract); XmlQualifiedName stableName; object[] genericParams; if(type.IsGenericTypeDefinition) { stableName = this.StableName; genericParams = paramContracts; } else { //partial Generic: Construct stable name from its open generic type definition stableName = DataContract.GetStableName(type.GetGenericTypeDefinition()); Type[] paramTypes = type.GetGenericArguments(); genericParams = new object[paramTypes.Length]; for(int i=0;i (Members.Count); foreach(DataMember member in Members) boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts)); } return boundClassContract; } } internal override bool Equals(object other, Dictionary checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) return true; if (base.Equals(other, checkedContracts)) { ClassDataContract dataContract = other as ClassDataContract; if (dataContract != null) { if (IsISerializable) { if (!dataContract.IsISerializable) return false; } else { if (dataContract.IsISerializable) return false; if (Members == null) { if (dataContract.Members != null) { // check that all the datamembers in dataContract.Members are optional if (!IsEveryDataMemberOptional(dataContract.Members)) return false; } } else if (dataContract.Members == null) { // check that all the datamembers in Members are optional if (!IsEveryDataMemberOptional(Members)) return false; } else { Dictionary membersDictionary = new Dictionary (Members.Count); List dataContractMembersList = new List (); for (int i = 0; i < Members.Count; i++) { membersDictionary.Add(Members[i].Name, Members[i]); } for (int i = 0; i < dataContract.Members.Count; i++) { // check that all datamembers common to both datacontracts match DataMember dataMember; if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember)) { if (dataMember.Equals(dataContract.Members[i], checkedContracts)) { membersDictionary.Remove(dataMember.Name); } else { return false; } } // otherwise save the non-matching datamembers for later verification else { dataContractMembersList.Add(dataContract.Members[i]); } } // check that datamembers left over from either datacontract are optional if (!IsEveryDataMemberOptional(membersDictionary.Values)) return false; if (!IsEveryDataMemberOptional(dataContractMembersList)) return false; } } if (BaseContract == null) return (dataContract.BaseContract == null); else if (dataContract.BaseContract == null) return false; else return BaseContract.Equals(dataContract.BaseContract, checkedContracts); } } return false; } bool IsEveryDataMemberOptional(IEnumerable dataMembers) { foreach (DataMember dataMember in dataMembers) { if (dataMember.IsRequired) return false; } return true; } public override int GetHashCode() { return base.GetHashCode(); } internal class DataMemberComparer : IComparer { public int Compare(DataMember x, DataMember y) { int orderCompare = x.Order - y.Order; if (orderCompare != 0) return orderCompare; return String.CompareOrdinal(x.Name, y.Name); } internal static DataMemberComparer Singleton = new DataMemberComparer(); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Runtime.Serialization { using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Security; using System.Threading; using System.Xml; using DataContractDictionary = System.Collections.Generic.Dictionary ; #if USE_REFEMIT public sealed class ClassDataContract : DataContract #else internal sealed class ClassDataContract : DataContract #endif { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members." + "statically cached and used from IL generated code. should ideally be Critical." + "marked SecurityNode to be callable from transparent IL generated code." + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")] public XmlDictionaryString[] ContractNamespaces; [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - XmlDictionaryString(s) representing the XML element names for class members." + "statically cached and used from IL generated code. should ideally be Critical." + "marked SecurityNode to be callable from transparent IL generated code." + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")] public XmlDictionaryString[] MemberNames; [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members." + "statically cached and used from IL generated code. should ideally be Critical." + "marked SecurityNode to be callable from transparent IL generated code." + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")] public XmlDictionaryString[] MemberNamespaces; [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML namespaces for members of class." + "Statically cached and used from IL generated code.")] [SecurityCritical] XmlDictionaryString[] childElementNamespaces; [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization. " + "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")] [SecurityCritical] ClassDataContractCriticalHelper helper; [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] internal ClassDataContract() : base(new ClassDataContractCriticalHelper()) { InitClassDataContract(); } [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] internal ClassDataContract(Type type) : base(new ClassDataContractCriticalHelper(type)) { InitClassDataContract(); } [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] ClassDataContract(Type type, XmlDictionaryString ns, string[] memberNames) : base(new ClassDataContractCriticalHelper(type, ns, memberNames)) { InitClassDataContract(); } [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")] [SecurityCritical] void InitClassDataContract() { this.helper = base.Helper as ClassDataContractCriticalHelper; this.ContractNamespaces = helper.ContractNamespaces; this.MemberNames = helper.MemberNames; this.MemberNamespaces = helper.MemberNamespaces; } internal ClassDataContract BaseContract { [Fx.Tag.SecurityNote(Critical = "Fetches the critical baseContract property.", Safe = "baseContract only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.BaseContract; } [Fx.Tag.SecurityNote(Critical = "Sets the critical baseContract property.")] [SecurityCritical] set { helper.BaseContract = value; } } internal List Members { [Fx.Tag.SecurityNote(Critical = "Fetches the critical members property.", Safe = "members only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.Members; } [Fx.Tag.SecurityNote(Critical = "Sets the critical members property.", Safe = "Protected for write if contract has underlyingType.")] [SecurityCritical] set { helper.Members = value; } } public XmlDictionaryString[] ChildElementNamespaces { [Fx.Tag.SecurityNote(Critical = "Sets the critical childElementNamespaces property.", Safe = "childElementNamespaces only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (this.childElementNamespaces == null) { lock (this) { if (this.childElementNamespaces == null) { if (helper.ChildElementNamespaces == null) { XmlDictionaryString[] tempChildElementamespaces = CreateChildElementNamespaces(); Thread.MemoryBarrier(); helper.ChildElementNamespaces = tempChildElementamespaces; } this.childElementNamespaces = helper.ChildElementNamespaces; } } } return this.childElementNamespaces; } } internal MethodInfo OnSerializing { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onSerializing property.", Safe = "onSerializing only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnSerializing; } } internal MethodInfo OnSerialized { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onSerialized property.", Safe = "onSerialized only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnSerialized; } } internal MethodInfo OnDeserializing { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onDeserializing property.", Safe = "onDeserializing only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnDeserializing; } } internal MethodInfo OnDeserialized { [Fx.Tag.SecurityNote(Critical = "Fetches the critical onDeserialized property.", Safe = "onDeserialized only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.OnDeserialized; } } internal MethodInfo ExtensionDataSetMethod { [Fx.Tag.SecurityNote(Critical = "Fetches the critical extensionDataSetMethod property.", Safe = "extensionDataSetMethod only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.ExtensionDataSetMethod; } } internal override DataContractDictionary KnownDataContracts { [Fx.Tag.SecurityNote(Critical = "Fetches the critical knownDataContracts property.", Safe = "knownDataContracts only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.KnownDataContracts; } [Fx.Tag.SecurityNote(Critical = "Sets the critical knownDataContracts property.", Safe = "Protected for write if contract has underlyingType.")] [SecurityCritical] set { helper.KnownDataContracts = value; } } internal override bool IsISerializable { [Fx.Tag.SecurityNote(Critical = "Fetches the critical isISerializable property.", Safe = "isISerializable only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.IsISerializable; } [Fx.Tag.SecurityNote(Critical = "Sets the critical isISerializable property.", Safe = "Protected for write if contract has underlyingType.")] [SecurityCritical] set { helper.IsISerializable = value; } } internal bool IsNonAttributedType { [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsNonAttributedType property.", Safe = "IsNonAttributedType only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.IsNonAttributedType; } } internal bool HasDataContract { [Fx.Tag.SecurityNote(Critical = "Fetches the critical hasDataContract property.", Safe = "hasDataContract only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.HasDataContract; } } internal bool HasExtensionData { [Fx.Tag.SecurityNote(Critical = "Fetches the critical hasExtensionData property.", Safe = "hasExtensionData only needs to be protected for write.")] [SecuritySafeCritical] get { return helper.HasExtensionData; } } [Fx.Tag.SecurityNote(Critical = "Fetches information about which constructor should be used to initialize ISerializable types.", Safe = "only needs to be protected for write.")] [SecuritySafeCritical] internal ConstructorInfo GetISerializableConstructor() { return helper.GetISerializableConstructor(); } [Fx.Tag.SecurityNote(Critical = "Fetches information about which constructor should be used to initialize non-attributed types that are valid for serialization.", Safe = "only needs to be protected for write.")] [SecuritySafeCritical] internal ConstructorInfo GetNonAttributedTypeConstructor() { return helper.GetNonAttributedTypeConstructor(); } internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate { [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatWriterDelegate property.", Safe = "xmlFormatWriterDelegate only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (helper.XmlFormatWriterDelegate == null) { lock (this) { if (helper.XmlFormatWriterDelegate == null) { XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this); Thread.MemoryBarrier(); helper.XmlFormatWriterDelegate = tempDelegate; } } } return helper.XmlFormatWriterDelegate; } } internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatReaderDelegate property.", Safe = "xmlFormatReaderDelegate only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (helper.XmlFormatReaderDelegate == null) { lock (this) { if (helper.XmlFormatReaderDelegate == null) { XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this); Thread.MemoryBarrier(); helper.XmlFormatReaderDelegate = tempDelegate; } } } return helper.XmlFormatReaderDelegate; } } internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames) { return new ClassDataContract(type, ns, memberNames); } internal static void CheckAndAddMember(List members, DataMember memberContract, Dictionary memberNamesTable) { DataMember existingMemberContract; if (memberNamesTable.TryGetValue(memberContract.Name, out existingMemberContract)) { Type declaringType = memberContract.MemberInfo.DeclaringType; DataContract.ThrowInvalidDataContractException( SR.GetString((declaringType.IsEnum ? SR.DupEnumMemberValue : SR.DupMemberName), existingMemberContract.MemberInfo.Name, memberContract.MemberInfo.Name, DataContract.GetClrTypeFullName(declaringType), memberContract.Name), declaringType); } memberNamesTable.Add(memberContract.Name, memberContract); members.Add(memberContract); } internal static XmlDictionaryString GetChildNamespaceToDeclare(DataContract dataContract, Type childType, XmlDictionary dictionary) { childType = DataContract.UnwrapNullableType(childType); if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType) && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull) { string ns = DataContract.GetStableName(childType).Namespace; if (ns.Length > 0 && ns != dataContract.Namespace.Value) return dictionary.Add(ns); } return null; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision." + "isNonAttributedType must be calculated correctly." + "IsNonAttributedTypeValidForSerialization is used as part of the isNonAttributedType calculation and is therefore marked with SecurityNote.", Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value.")] // check whether a corresponding update is required in DataContractCriticalHelper.CreateDataContract static internal bool IsNonAttributedTypeValidForSerialization(Type type) { if (type.IsArray) return false; if (type.IsEnum) return false; if (type.IsGenericParameter) return false; if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) return false; if (type.IsPointer) return false; if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) return false; Type[] interfaceTypes = type.GetInterfaces(); foreach (Type interfaceType in interfaceTypes) { if (CollectionDataContract.IsCollectionInterface(interfaceType)) return false; } if (type.IsSerializable) return false; if (Globals.TypeOfISerializable.IsAssignableFrom(type)) return false; if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) return false; if (type == Globals.TypeOfExtensionDataObject) return false; if (type.IsValueType) { return type.IsVisible; } else { return (type.IsVisible && type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null) != null); } } XmlDictionaryString[] CreateChildElementNamespaces() { if (Members == null) return null; XmlDictionaryString[] baseChildElementNamespaces = null; if (this.BaseContract != null) baseChildElementNamespaces = this.BaseContract.ChildElementNamespaces; int baseChildElementNamespaceCount = (baseChildElementNamespaces != null) ? baseChildElementNamespaces.Length : 0; XmlDictionaryString[] childElementNamespaces = new XmlDictionaryString[Members.Count + baseChildElementNamespaceCount]; if (baseChildElementNamespaceCount > 0) Array.Copy(baseChildElementNamespaces, 0, childElementNamespaces, 0, baseChildElementNamespaces.Length); XmlDictionary dictionary = new XmlDictionary(); for (int i = 0; i < this.Members.Count; i++) { childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, this.Members[i].MemberType, dictionary); } return childElementNamespaces; } [Fx.Tag.SecurityNote(Critical = "Calls critical method on helper.", Safe = "Doesn't leak anything.")] [SecuritySafeCritical] void EnsureMethodsImported() { helper.EnsureMethodsImported(); } public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) { XmlFormatWriterDelegate(xmlWriter, obj, context, this); } public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) { xmlReader.Read(); object o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces); xmlReader.ReadEndElement(); return o; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for deserialization." + "Since this information is used to determine whether to give the generated code access " + "permissions to private members, any changes to the logic should be reviewed.")] internal bool RequiresMemberAccessForRead(SecurityException securityException) { EnsureMethodsImported(); if (!IsTypeVisible(UnderlyingType)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException)) return true; if (ConstructorRequiresMemberAccess(GetISerializableConstructor())) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustISerializableNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor())) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustNonAttributedSerializableTypeNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (MethodRequiresMemberAccess(this.OnDeserializing)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnDeserializingNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.OnDeserializing.Name), securityException)); } return true; } if (MethodRequiresMemberAccess(this.OnDeserialized)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnDeserializedNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.OnDeserialized.Name), securityException)); } return true; } if (this.Members != null) { for (int i = 0; i < this.Members.Count; i++) { if (this.Members[i].RequiresMemberAccessForSet()) { if (securityException != null) { if (this.Members[i].MemberInfo is FieldInfo) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractFieldSetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractPropertySetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } } return true; } } } return false; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for serialization." + " Since this information is used to determine whether to give the generated code access" + " permissions to private members, any changes to the logic should be reviewed.")] internal bool RequiresMemberAccessForWrite(SecurityException securityException) { EnsureMethodsImported(); if (!IsTypeVisible(UnderlyingType)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)), securityException)); } return true; } if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForWrite(securityException)) return true; if (MethodRequiresMemberAccess(this.OnSerializing)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnSerializingNotPublic, DataContract.GetClrTypeFullName(this.UnderlyingType), this.OnSerializing.Name), securityException)); } return true; } if (MethodRequiresMemberAccess(this.OnSerialized)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractOnSerializedNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.OnSerialized.Name), securityException)); } return true; } if (this.Members != null) { for (int i = 0; i < this.Members.Count; i++) { if (this.Members[i].RequiresMemberAccessForGet()) { if (securityException != null) { if (this.Members[i].MemberInfo is FieldInfo) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractFieldGetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.GetString( SR.PartialTrustDataContractPropertyGetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), this.Members[i].MemberInfo.Name), securityException)); } } return true; } } } return false; } [Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing classes." + " Since the data is cached statically, we lock down access to it.")] [SecurityCritical(SecurityCriticalScope.Everything)] class ClassDataContractCriticalHelper : DataContract.DataContractCriticalHelper { ClassDataContract baseContract; List members; MethodInfo onSerializing, onSerialized; MethodInfo onDeserializing, onDeserialized; MethodInfo extensionDataSetMethod; DataContractDictionary knownDataContracts; bool isISerializable; bool isKnownTypeAttributeChecked; bool isMethodChecked; bool hasExtensionData; [Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and hasDataContract.")] bool isNonAttributedType; [Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and isNonAttributedType.")] bool hasDataContract; XmlDictionaryString[] childElementNamespaces; XmlFormatClassReaderDelegate xmlFormatReaderDelegate; XmlFormatClassWriterDelegate xmlFormatWriterDelegate; public XmlDictionaryString[] ContractNamespaces; public XmlDictionaryString[] MemberNames; public XmlDictionaryString[] MemberNamespaces; internal ClassDataContractCriticalHelper() : base() { } internal ClassDataContractCriticalHelper(Type type) : base(type) { XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type); if (type == Globals.TypeOfDBNull) { this.StableName = stableName; this.members = new List (); XmlDictionary dictionary = new XmlDictionary(2); this.Name = dictionary.Add(StableName.Name); this.Namespace = dictionary.Add(StableName.Namespace); this.ContractNamespaces = this.MemberNames = this.MemberNamespaces = new XmlDictionaryString[] { }; EnsureMethodsImported(); return; } Type baseType = type.BaseType; this.isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type)); SetIsNonAttributedType(type); if (this.isISerializable) { if (HasDataContract) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ISerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type)))); if (baseType != null && !(baseType.IsSerializable && Globals.TypeOfISerializable.IsAssignableFrom(baseType))) baseType = null; } this.IsValueType = type.IsValueType; if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) { DataContract baseContract = DataContract.GetDataContract(baseType); if (baseContract is CollectionDataContract) this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract; else this.BaseContract = baseContract as ClassDataContract; if (this.BaseContract != null && this.BaseContract.IsNonAttributedType && !this.isNonAttributedType) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError (new InvalidDataContractException(SR.GetString(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes, DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(baseType)))); } } else this.BaseContract = null; hasExtensionData = (Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(type)); if (hasExtensionData && !HasDataContract && !IsNonAttributedType) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.OnlyDataContractTypesCanHaveExtensionData, DataContract.GetClrTypeFullName(type)))); if (this.isISerializable) SetDataContractName(stableName); else { this.StableName = stableName; ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); Name = dictionary.Add(StableName.Name); Namespace = dictionary.Add(StableName.Namespace); int baseMemberCount = 0; int baseContractCount = 0; if (BaseContract == null) { MemberNames = new XmlDictionaryString[Members.Count]; MemberNamespaces = new XmlDictionaryString[Members.Count]; ContractNamespaces = new XmlDictionaryString[1]; } else { baseMemberCount = BaseContract.MemberNames.Length; MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount]; Array.Copy(BaseContract.MemberNames, MemberNames, baseMemberCount); MemberNamespaces = new XmlDictionaryString[Members.Count + baseMemberCount]; Array.Copy(BaseContract.MemberNamespaces, MemberNamespaces, baseMemberCount); baseContractCount = BaseContract.ContractNamespaces.Length; ContractNamespaces = new XmlDictionaryString[1 + baseContractCount]; Array.Copy(BaseContract.ContractNamespaces, ContractNamespaces, baseContractCount); } ContractNamespaces[baseContractCount] = Namespace; for (int i = 0; i < Members.Count; i++) { MemberNames[i + baseMemberCount] = dictionary.Add(Members[i].Name); MemberNamespaces[i + baseMemberCount] = Namespace; } } EnsureMethodsImported(); } internal ClassDataContractCriticalHelper(Type type, XmlDictionaryString ns, string[] memberNames) : base(type) { this.StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value); ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(1 + Members.Count); Name = dictionary.Add(StableName.Name); Namespace = ns; ContractNamespaces = new XmlDictionaryString[] { Namespace }; MemberNames = new XmlDictionaryString[Members.Count]; MemberNamespaces = new XmlDictionaryString[Members.Count]; for (int i = 0; i < Members.Count; i++) { Members[i].Name = memberNames[i]; MemberNames[i] = dictionary.Add(Members[i].Name); MemberNamespaces[i] = Namespace; } EnsureMethodsImported(); } void EnsureIsReferenceImported(Type type) { DataContractAttribute dataContractAttribute; bool isReference = false; bool hasDataContractAttribute = TryGetDCAttribute(type, out dataContractAttribute); if (BaseContract != null) { if (hasDataContractAttribute && dataContractAttribute.IsReferenceSetExplicit) { bool baseIsReference = this.BaseContract.IsReference; if ((baseIsReference && !dataContractAttribute.IsReference) || (!baseIsReference && dataContractAttribute.IsReference)) { DataContract.ThrowInvalidDataContractException( SR.GetString(SR.InconsistentIsReference, DataContract.GetClrTypeFullName(type), dataContractAttribute.IsReference, DataContract.GetClrTypeFullName(this.BaseContract.UnderlyingType), this.BaseContract.IsReference), type); } else { isReference = dataContractAttribute.IsReference; } } else { isReference = this.BaseContract.IsReference; } } else if (hasDataContractAttribute) { if (dataContractAttribute.IsReference) isReference = dataContractAttribute.IsReference; } if (isReference && type.IsValueType) { DataContract.ThrowInvalidDataContractException( SR.GetString(SR.ValueTypeCannotHaveIsReference, DataContract.GetClrTypeFullName(type), true, false), type); return; } this.IsReference = isReference; } void ImportDataMembers() { Type type = this.UnderlyingType; EnsureIsReferenceImported(type); List tempMembers = new List (); Dictionary memberNamesTable = new Dictionary (); MemberInfo[] memberInfos; if (this.isNonAttributedType) { memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); } else { memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } for (int i = 0; i < memberInfos.Length; i++) { MemberInfo member = memberInfos[i]; if (HasDataContract) { object[] memberAttributes = member.GetCustomAttributes(typeof(DataMemberAttribute), false); if (memberAttributes != null && memberAttributes.Length > 0) { if (memberAttributes.Length > 1) ThrowInvalidDataContractException(SR.GetString(SR.TooManyDataMembers, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name)); DataMember memberContract = new DataMember(member); if (member.MemberType == MemberTypes.Property) { PropertyInfo property = (PropertyInfo)member; MethodInfo getMethod = property.GetGetMethod(true); if (getMethod != null && IsMethodOverriding(getMethod)) continue; MethodInfo setMethod = property.GetSetMethod(true); if (setMethod != null && IsMethodOverriding(setMethod)) continue; if (getMethod == null) ThrowInvalidDataContractException(SR.GetString(SR.NoGetMethodForProperty, property.DeclaringType, property.Name)); if (setMethod == null) { if (!SetIfGetOnlyCollection(memberContract)) { ThrowInvalidDataContractException(SR.GetString(SR.NoSetMethodForProperty, property.DeclaringType, property.Name)); } } if (getMethod.GetParameters().Length > 0) ThrowInvalidDataContractException(SR.GetString(SR.IndexedPropertyCannotBeSerialized, property.DeclaringType, property.Name)); } else if (member.MemberType != MemberTypes.Field) ThrowInvalidDataContractException(SR.GetString(SR.InvalidMember, DataContract.GetClrTypeFullName(type), member.Name)); DataMemberAttribute memberAttribute = (DataMemberAttribute)memberAttributes[0]; if (memberAttribute.IsNameSetExplicit) { if (memberAttribute.Name == null || memberAttribute.Name.Length == 0) ThrowInvalidDataContractException(SR.GetString(SR.InvalidDataMemberName, member.Name, DataContract.GetClrTypeFullName(type))); memberContract.Name = memberAttribute.Name; } else memberContract.Name = member.Name; memberContract.Name = DataContract.EncodeLocalName(memberContract.Name); memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); memberContract.IsRequired = memberAttribute.IsRequired; if (memberAttribute.IsRequired && this.IsReference) { ThrowInvalidDataContractException( SR.GetString(SR.IsRequiredDataMemberOnIsReferenceDataContractType, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name, true), type); } memberContract.EmitDefaultValue = memberAttribute.EmitDefaultValue; memberContract.Order = memberAttribute.Order; CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } } else if (this.isNonAttributedType) { FieldInfo field = member as FieldInfo; PropertyInfo property = member as PropertyInfo; if ((field == null && property == null) || (field != null && field.IsInitOnly)) continue; object[] memberAttributes = member.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false); if (memberAttributes != null && memberAttributes.Length > 0) { if (memberAttributes.Length > 1) ThrowInvalidDataContractException(SR.GetString(SR.TooManyIgnoreDataMemberAttributes, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name)); else continue; } DataMember memberContract = new DataMember(member); if (property != null) { MethodInfo getMethod = property.GetGetMethod(); if (getMethod == null || IsMethodOverriding(getMethod) || getMethod.GetParameters().Length > 0) continue; MethodInfo setMethod = property.GetSetMethod(true); if (setMethod == null) { if (!SetIfGetOnlyCollection(memberContract)) continue; } else { if (!setMethod.IsPublic || IsMethodOverriding(setMethod)) continue; } //skip ExtensionData member of type ExtensionDataObject if IExtensibleDataObject is implemented in non-attributed type if (this.hasExtensionData && memberContract.MemberType == Globals.TypeOfExtensionDataObject && member.Name == Globals.ExtensionDataObjectPropertyName) continue; } memberContract.Name = DataContract.EncodeLocalName(member.Name); memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } else { FieldInfo field = member as FieldInfo; if (field != null && !field.IsNotSerialized) { DataMember memberContract = new DataMember(member); memberContract.Name = DataContract.EncodeLocalName(member.Name); object[] optionalFields = field.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false); if (optionalFields == null || optionalFields.Length == 0) { if (this.IsReference) { ThrowInvalidDataContractException( SR.GetString(SR.NonOptionalFieldMemberOnIsReferenceSerializableType, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name, true), type); } memberContract.IsRequired = true; } memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } } } if (tempMembers.Count > 1) tempMembers.Sort(DataMemberComparer.Singleton); SetIfMembersHaveConflict(tempMembers); Thread.MemoryBarrier(); members = tempMembers; } bool SetIfGetOnlyCollection(DataMember memberContract) { //OK to call IsCollection here since the use of surrogated collection types is not supported in get-only scenarios if (CollectionDataContract.IsCollection(memberContract.MemberType, false /*isConstructorRequired*/) && !memberContract.MemberType.IsValueType) { memberContract.IsGetOnlyCollection = true; return true; } return false; } void SetIfMembersHaveConflict(List members) { if (BaseContract == null) return; int baseTypeIndex = 0; List membersInHierarchy = new List (); foreach (DataMember member in members) { membersInHierarchy.Add(new Member(member, this.StableName.Namespace, baseTypeIndex)); } ClassDataContract currContract = BaseContract; while (currContract != null) { baseTypeIndex++; foreach (DataMember member in currContract.Members) { membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex)); } currContract = currContract.BaseContract; } IComparer comparer = DataMemberConflictComparer.Singleton; membersInHierarchy.Sort(comparer); for (int i = 0; i < membersInHierarchy.Count - 1; i++) { int startIndex = i; int endIndex = i; bool hasConflictingType = false; while (endIndex < membersInHierarchy.Count - 1 && String.CompareOrdinal(membersInHierarchy[endIndex].member.Name, membersInHierarchy[endIndex + 1].member.Name) == 0 && String.CompareOrdinal(membersInHierarchy[endIndex].ns, membersInHierarchy[endIndex + 1].ns) == 0) { membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member; if (!hasConflictingType) { if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType) { hasConflictingType = true; } else { hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType); } } endIndex++; } if (hasConflictingType) { for (int j = startIndex; j <= endIndex; j++) { membersInHierarchy[j].member.HasConflictingNameAndType = true; } } i = endIndex + 1; } } [Fx.Tag.SecurityNote(Critical = "Sets the critical hasDataContract field.", Safe = "Uses a trusted critical API (DataContract.GetStableName) to calculate the value, does not accept the value from the caller.")] [SecuritySafeCritical] XmlQualifiedName GetStableNameAndSetHasDataContract(Type type) { return DataContract.GetStableName(type, out this.hasDataContract); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision." + "isNonAttributedType must be calculated correctly." + "SetIsNonAttributedType should not be called before GetStableNameAndSetHasDataContract since it is dependent on the correct calculation of hasDataContract.", Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value.")] void SetIsNonAttributedType(Type type) { this.isNonAttributedType = !type.IsSerializable && !this.hasDataContract && IsNonAttributedTypeValidForSerialization(type); } static bool IsMethodOverriding(MethodInfo method) { return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0); } internal void EnsureMethodsImported() { if (!isMethodChecked && UnderlyingType != null) { lock (this) { if (!isMethodChecked) { Type type = this.UnderlyingType; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); for (int i=0;i Members { get { return members; } set { members = value; } } internal MethodInfo OnSerializing { get { EnsureMethodsImported(); return onSerializing; } } internal MethodInfo OnSerialized { get { EnsureMethodsImported(); return onSerialized; } } internal MethodInfo OnDeserializing { get { EnsureMethodsImported(); return onDeserializing; } } internal MethodInfo OnDeserialized { get { EnsureMethodsImported(); return onDeserialized; } } internal MethodInfo ExtensionDataSetMethod { get { EnsureMethodsImported(); return extensionDataSetMethod; } } internal override DataContractDictionary KnownDataContracts { get { if (!isKnownTypeAttributeChecked && UnderlyingType != null) { lock (this) { if (!isKnownTypeAttributeChecked) { knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType); Thread.MemoryBarrier(); isKnownTypeAttributeChecked = true; } } } return knownDataContracts; } set { knownDataContracts = value; } } internal override bool IsISerializable { get { return isISerializable; } set { isISerializable = value; } } internal bool HasDataContract { get { return hasDataContract; } } internal bool HasExtensionData { get { return hasExtensionData; } } internal bool IsNonAttributedType { get { return isNonAttributedType; } } internal ConstructorInfo GetISerializableConstructor() { if (!IsISerializable) return null; ConstructorInfo ctor = UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, SerInfoCtorArgs, null); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(UnderlyingType)))); return ctor; } internal ConstructorInfo GetNonAttributedTypeConstructor() { if (!this.IsNonAttributedType) return null; Type type = UnderlyingType; if (type.IsValueType) return null; ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); return ctor; } internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate { get { return xmlFormatWriterDelegate; } set { xmlFormatWriterDelegate = value; } } internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { get { return xmlFormatReaderDelegate; } set { xmlFormatReaderDelegate = value; } } public XmlDictionaryString[] ChildElementNamespaces { get { return childElementNamespaces; } set { childElementNamespaces = value; } } static Type[] serInfoCtorArgs; static Type[] SerInfoCtorArgs { get { if (serInfoCtorArgs == null) serInfoCtorArgs = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; return serInfoCtorArgs; } } internal struct Member { internal Member(DataMember member, string ns, int baseTypeIndex) { this.member = member; this.ns = ns; this.baseTypeIndex = baseTypeIndex; } internal DataMember member; internal string ns; internal int baseTypeIndex; } internal class DataMemberConflictComparer : IComparer { public int Compare(Member x, Member y) { int nsCompare = String.CompareOrdinal(x.ns, y.ns); if (nsCompare != 0) return nsCompare; int nameCompare = String.CompareOrdinal(x.member.Name, y.member.Name); if (nameCompare != 0) return nameCompare; return x.baseTypeIndex - y.baseTypeIndex; } internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer(); } } [Fx.Tag.SecurityNote(Critical = "Sets critical properties on ClassDataContract .", Safe = "Called during schema import/code generation.")] [SecuritySafeCritical] internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { Type type = UnderlyingType; if(!type.IsGenericType || !type.ContainsGenericParameters) return this; lock(this) { DataContract boundContract; if(boundContracts.TryGetValue(this, out boundContract)) return boundContract; ClassDataContract boundClassContract = new ClassDataContract(); boundContracts.Add(this, boundClassContract); XmlQualifiedName stableName; object[] genericParams; if(type.IsGenericTypeDefinition) { stableName = this.StableName; genericParams = paramContracts; } else { //partial Generic: Construct stable name from its open generic type definition stableName = DataContract.GetStableName(type.GetGenericTypeDefinition()); Type[] paramTypes = type.GetGenericArguments(); genericParams = new object[paramTypes.Length]; for(int i=0;i (Members.Count); foreach(DataMember member in Members) boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts)); } return boundClassContract; } } internal override bool Equals(object other, Dictionary checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) return true; if (base.Equals(other, checkedContracts)) { ClassDataContract dataContract = other as ClassDataContract; if (dataContract != null) { if (IsISerializable) { if (!dataContract.IsISerializable) return false; } else { if (dataContract.IsISerializable) return false; if (Members == null) { if (dataContract.Members != null) { // check that all the datamembers in dataContract.Members are optional if (!IsEveryDataMemberOptional(dataContract.Members)) return false; } } else if (dataContract.Members == null) { // check that all the datamembers in Members are optional if (!IsEveryDataMemberOptional(Members)) return false; } else { Dictionary membersDictionary = new Dictionary (Members.Count); List dataContractMembersList = new List (); for (int i = 0; i < Members.Count; i++) { membersDictionary.Add(Members[i].Name, Members[i]); } for (int i = 0; i < dataContract.Members.Count; i++) { // check that all datamembers common to both datacontracts match DataMember dataMember; if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember)) { if (dataMember.Equals(dataContract.Members[i], checkedContracts)) { membersDictionary.Remove(dataMember.Name); } else { return false; } } // otherwise save the non-matching datamembers for later verification else { dataContractMembersList.Add(dataContract.Members[i]); } } // check that datamembers left over from either datacontract are optional if (!IsEveryDataMemberOptional(membersDictionary.Values)) return false; if (!IsEveryDataMemberOptional(dataContractMembersList)) return false; } } if (BaseContract == null) return (dataContract.BaseContract == null); else if (dataContract.BaseContract == null) return false; else return BaseContract.Equals(dataContract.BaseContract, checkedContracts); } } return false; } bool IsEveryDataMemberOptional(IEnumerable dataMembers) { foreach (DataMember dataMember in dataMembers) { if (dataMember.IsRequired) return false; } return true; } public override int GetHashCode() { return base.GetHashCode(); } internal class DataMemberComparer : IComparer { public int Compare(DataMember x, DataMember y) { int orderCompare = x.Order - y.Order; if (orderCompare != 0) return orderCompare; return String.CompareOrdinal(x.Name, y.Name); } internal static DataMemberComparer Singleton = new DataMemberComparer(); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Int32RectConverter.cs
- NetSectionGroup.cs
- DataGridViewLayoutData.cs
- base64Transforms.cs
- DataGridViewSelectedRowCollection.cs
- SqlCacheDependencyDatabase.cs
- DecoderBestFitFallback.cs
- HttpListener.cs
- ListBox.cs
- CodeCatchClause.cs
- ValueChangedEventManager.cs
- CodeTryCatchFinallyStatement.cs
- SiteMapNodeItemEventArgs.cs
- DESCryptoServiceProvider.cs
- UserInitiatedNavigationPermission.cs
- ColorAnimationBase.cs
- SettingsPropertyIsReadOnlyException.cs
- Font.cs
- OdbcDataAdapter.cs
- Util.cs
- Aggregates.cs
- ClientConvert.cs
- EventHandlerList.cs
- FormatException.cs
- JsonServiceDocumentSerializer.cs
- SQLGuidStorage.cs
- Hashtable.cs
- ProviderException.cs
- DbConvert.cs
- IgnoreSectionHandler.cs
- ImageCreator.cs
- SByte.cs
- PageThemeBuildProvider.cs
- InstanceData.cs
- HostedHttpTransportManager.cs
- ConsoleCancelEventArgs.cs
- AnimationClockResource.cs
- PageThemeCodeDomTreeGenerator.cs
- CommandID.cs
- EmptyCollection.cs
- RawStylusInputCustomDataList.cs
- ImageSource.cs
- HttpCapabilitiesSectionHandler.cs
- BitmapMetadataEnumerator.cs
- ProjectionPathBuilder.cs
- SingleResultAttribute.cs
- RoleGroupCollection.cs
- TraceInternal.cs
- WebPartHelpVerb.cs
- XmlSchemaAll.cs
- CopyOfAction.cs
- IntSecurity.cs
- HebrewCalendar.cs
- XamlTypeMapper.cs
- StorageEntityTypeMapping.cs
- PolicyException.cs
- TypePropertyEditor.cs
- ContentTextAutomationPeer.cs
- DetailsView.cs
- TaiwanCalendar.cs
- ReflectionPermission.cs
- FieldAccessException.cs
- DataSetSchema.cs
- Mutex.cs
- LogConverter.cs
- AssemblyAssociatedContentFileAttribute.cs
- ThicknessAnimationBase.cs
- BaseCodePageEncoding.cs
- EditorZone.cs
- StringUtil.cs
- TextFragmentEngine.cs
- AdRotatorDesigner.cs
- ReadOnlyHierarchicalDataSource.cs
- AbstractExpressions.cs
- StructureChangedEventArgs.cs
- XsltLoader.cs
- HtmlValidationSummaryAdapter.cs
- TextRangeProviderWrapper.cs
- Drawing.cs
- TimeoutValidationAttribute.cs
- HtmlInputHidden.cs
- DrawingCollection.cs
- DbConnectionStringBuilder.cs
- SafeNativeMethodsMilCoreApi.cs
- XPathException.cs
- AsyncPostBackErrorEventArgs.cs
- GridViewColumnHeader.cs
- Win32Exception.cs
- UnaryNode.cs
- OptimizerPatterns.cs
- XmlName.cs
- BitmapDecoder.cs
- UDPClient.cs
- SqlRetyper.cs
- rsa.cs
- RegexParser.cs
- ScalarConstant.cs
- SerializationInfoEnumerator.cs
- WindowsImpersonationContext.cs
- ListViewGroupItemCollection.cs