//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.Runtime.Serialization { using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.Diagnostics; using System.ServiceModel.Diagnostics; using System.Security; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using System.Runtime.Serialization.Diagnostics; class SchemaExporter { XmlSchemaSet schemas; XmlDocument xmlDoc; DataContractSet dataContractSet; internal SchemaExporter(XmlSchemaSet schemas, DataContractSet dataContractSet) { this.schemas = schemas; this.dataContractSet = dataContractSet; } XmlSchemaSet Schemas { get { return schemas; } } XmlDocument XmlDoc { get { if (xmlDoc == null) xmlDoc = new XmlDocument(); return xmlDoc; } } internal void Export() { try { // Remove this if we decide to publish serialization schema at well-known location ExportSerializationSchema(); foreach (KeyValuePair pair in dataContractSet) { DataContract dataContract = pair.Value; if (!dataContractSet.IsContractProcessed(dataContract)) { ExportDataContract(dataContract); dataContractSet.SetContractProcessed(dataContract); } } } finally { xmlDoc = null; dataContractSet = null; } } void ExportSerializationSchema() { if (!Schemas.Contains(Globals.SerializationNamespace)) { StringReader reader = new StringReader(Globals.SerializationSchema); XmlSchema schema = XmlSchema.Read(reader, null); if (schema == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace))); Schemas.Add(schema); } } void ExportDataContract(DataContract dataContract) { if (dataContract.IsBuiltInDataContract) return; else if (dataContract is XmlDataContract) ExportXmlDataContract((XmlDataContract)dataContract); else { XmlSchema schema = GetSchema(dataContract.StableName.Namespace); if (dataContract is ClassDataContract) { ClassDataContract classDataContract = (ClassDataContract)dataContract; if (classDataContract.IsISerializable) ExportISerializableDataContract(classDataContract, schema); else ExportClassDataContract(classDataContract, schema); } else if (dataContract is CollectionDataContract) ExportCollectionDataContract((CollectionDataContract)dataContract, schema); else if (dataContract is EnumDataContract) ExportEnumDataContract((EnumDataContract)dataContract, schema); ExportTopLevelElement(dataContract, schema); Schemas.Reprocess(schema); } } XmlSchemaElement ExportTopLevelElement(DataContract dataContract, XmlSchema schema) { if (schema == null || dataContract.StableName.Namespace != dataContract.TopLevelElementNamespace.Value) schema = GetSchema(dataContract.TopLevelElementNamespace.Value); XmlSchemaElement topLevelElement = new XmlSchemaElement(); topLevelElement.Name = dataContract.TopLevelElementName.Value; SetElementType(topLevelElement, dataContract, schema); topLevelElement.IsNillable = true; schema.Items.Add(topLevelElement); return topLevelElement; } void ExportClassDataContract(ClassDataContract classDataContract, XmlSchema schema) { XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = classDataContract.StableName.Name; schema.Items.Add(type); XmlElement genericInfoElement = null; if (classDataContract.UnderlyingType.IsGenericType) genericInfoElement = ExportGenericInfo(classDataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); XmlSchemaSequence rootSequence = new XmlSchemaSequence(); for (int i = 0; i < classDataContract.Members.Count; i++) { DataMember dataMember = classDataContract.Members[i]; XmlSchemaElement element = new XmlSchemaElement(); element.Name = dataMember.Name; XmlElement actualTypeElement = null; DataContract memberTypeContract = dataContractSet.GetMemberTypeDataContract(dataMember); if (CheckIfMemberHasConflict(dataMember)) { element.SchemaTypeName = AnytypeQualifiedName; actualTypeElement = ExportActualType(memberTypeContract.StableName); SchemaHelper.AddSchemaImport(memberTypeContract.StableName.Namespace, schema); } else SetElementType(element, memberTypeContract, schema); SchemaHelper.AddElementForm(element, schema); if (dataMember.IsNullable) element.IsNillable = true; if (!dataMember.IsRequired) element.MinOccurs = 0; element.Annotation = GetSchemaAnnotation(actualTypeElement, ExportSurrogateData(dataMember), ExportEmitDefaultValue(dataMember)); rootSequence.Items.Add(element); } XmlElement isValueTypeElement = null; if (classDataContract.BaseContract != null) { XmlSchemaComplexContentExtension extension = CreateTypeContent(type, classDataContract.BaseContract.StableName, schema); extension.Particle = rootSequence; if (classDataContract.IsReference && !classDataContract.BaseContract.IsReference) { AddReferenceAttributes(extension.Attributes, schema); } } else { type.Particle = rootSequence; if (classDataContract.IsValueType) isValueTypeElement = GetAnnotationMarkup(IsValueTypeName, XmlConvert.ToString(classDataContract.IsValueType), schema); if (classDataContract.IsReference) AddReferenceAttributes(type.Attributes, schema); } type.Annotation = GetSchemaAnnotation(genericInfoElement, ExportSurrogateData(classDataContract), isValueTypeElement); } void AddReferenceAttributes(XmlSchemaObjectCollection attributes, XmlSchema schema) { SchemaHelper.AddSchemaImport(Globals.SerializationNamespace, schema); schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); attributes.Add(IdAttribute); attributes.Add(RefAttribute); } void SetElementType(XmlSchemaElement element, DataContract dataContract, XmlSchema schema) { XmlDataContract xmlDataContract = dataContract as XmlDataContract; if (xmlDataContract != null && xmlDataContract.IsAnonymous) { element.SchemaType = xmlDataContract.XsdType; } else { element.SchemaTypeName = dataContract.StableName; if (element.SchemaTypeName.Namespace.Equals(Globals.SerializationNamespace)) schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); SchemaHelper.AddSchemaImport(dataContract.StableName.Namespace, schema); } } bool CheckIfMemberHasConflict(DataMember dataMember) { if (dataMember.HasConflictingNameAndType) return true; DataMember conflictingMember = dataMember.ConflictingMember; while (conflictingMember != null) { if (conflictingMember.HasConflictingNameAndType) return true; conflictingMember = conflictingMember.ConflictingMember; } return false; } private XmlElement ExportEmitDefaultValue(DataMember dataMember) { if (dataMember.EmitDefaultValue) return null; XmlElement defaultValueElement = XmlDoc.CreateElement(DefaultValueAnnotation.Name, DefaultValueAnnotation.Namespace); XmlAttribute emitDefaultValueAttribute = XmlDoc.CreateAttribute(Globals.EmitDefaultValueAttribute); emitDefaultValueAttribute.Value = Globals.False; defaultValueElement.Attributes.Append(emitDefaultValueAttribute); return defaultValueElement; } XmlElement ExportActualType(XmlQualifiedName typeName) { return ExportActualType(typeName, XmlDoc); } static XmlElement ExportActualType(XmlQualifiedName typeName, XmlDocument xmlDoc) { XmlElement actualTypeElement = xmlDoc.CreateElement(ActualTypeAnnotationName.Name, ActualTypeAnnotationName.Namespace); XmlAttribute nameAttribute = xmlDoc.CreateAttribute(Globals.ActualTypeNameAttribute); nameAttribute.Value = typeName.Name; actualTypeElement.Attributes.Append(nameAttribute); XmlAttribute nsAttribute = xmlDoc.CreateAttribute(Globals.ActualTypeNamespaceAttribute); nsAttribute.Value = typeName.Namespace; actualTypeElement.Attributes.Append(nsAttribute); return actualTypeElement; } XmlElement ExportGenericInfo(Type clrType, string elementName, string elementNs) { Type itemType; int nestedCollectionLevel = 0; while (CollectionDataContract.IsCollection(clrType, out itemType)) { if (DataContract.GetBuiltInDataContract(clrType) != null || CollectionDataContract.IsCollectionDataContract(clrType)) { break; } clrType = itemType; nestedCollectionLevel++; } Type[] genericArguments = null; IList genericArgumentCounts = null; if (clrType.IsGenericType) { genericArguments = clrType.GetGenericArguments(); string typeName; if (clrType.DeclaringType == null) typeName = clrType.Name; else { int nsLen = (clrType.Namespace == null) ? 0 : clrType.Namespace.Length; if (nsLen > 0) nsLen++; //include the . following namespace typeName = DataContract.GetClrTypeFullName(clrType).Substring(nsLen).Replace('+', '.'); } int iParam = typeName.IndexOf('['); if (iParam >= 0) typeName = typeName.Substring(0, iParam); genericArgumentCounts = DataContract.GetDataContractNameForGenericName(typeName, null); clrType = clrType.GetGenericTypeDefinition(); } XmlQualifiedName dcqname = DataContract.GetStableName(clrType); if (nestedCollectionLevel > 0) { string collectionName = dcqname.Name; for (int n = 0; n < nestedCollectionLevel; n++) collectionName = Globals.ArrayPrefix + collectionName; dcqname = new XmlQualifiedName(collectionName, DataContract.GetCollectionNamespace(dcqname.Namespace)); } XmlElement typeElement = XmlDoc.CreateElement(elementName, elementNs); XmlAttribute nameAttribute = XmlDoc.CreateAttribute(Globals.GenericNameAttribute); nameAttribute.Value = genericArguments != null ? XmlConvert.DecodeName(dcqname.Name) : dcqname.Name; //nameAttribute.Value = dcqname.Name; typeElement.Attributes.Append(nameAttribute); XmlAttribute nsAttribute = XmlDoc.CreateAttribute(Globals.GenericNamespaceAttribute); nsAttribute.Value = dcqname.Namespace; typeElement.Attributes.Append(nsAttribute); if (genericArguments != null) { int argIndex = 0; int nestedLevel = 0; foreach (int genericArgumentCount in genericArgumentCounts) { for (int i = 0; i < genericArgumentCount; i++, argIndex++) { XmlElement argumentElement = ExportGenericInfo(genericArguments[argIndex], Globals.GenericParameterLocalName, Globals.SerializationNamespace); if (nestedLevel > 0) { XmlAttribute nestedLevelAttribute = XmlDoc.CreateAttribute(Globals.GenericParameterNestedLevelAttribute); nestedLevelAttribute.Value = nestedLevel.ToString(CultureInfo.InvariantCulture); argumentElement.Attributes.Append(nestedLevelAttribute); } typeElement.AppendChild(argumentElement); } nestedLevel++; } if (genericArgumentCounts[nestedLevel - 1] == 0) { XmlAttribute typeNestedLevelsAttribute = XmlDoc.CreateAttribute(Globals.GenericParameterNestedLevelAttribute); typeNestedLevelsAttribute.Value = genericArgumentCounts.Count.ToString(CultureInfo.InvariantCulture); typeElement.Attributes.Append(typeNestedLevelsAttribute); } } return typeElement; } XmlElement ExportSurrogateData(object key) { object surrogateData = dataContractSet.GetSurrogateData(key); if (surrogateData == null) return null; StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); XmlWriterSettings writerSettings = new XmlWriterSettings(); writerSettings.OmitXmlDeclaration = true; XmlWriter xmlWriter = XmlWriter.Create(stringWriter, writerSettings); Collection knownTypes = new Collection(); DataContractSurrogateCaller.GetKnownCustomDataTypes(dataContractSet.DataContractSurrogate, knownTypes); DataContractSerializer serializer = new DataContractSerializer(Globals.TypeOfObject, SurrogateDataAnnotationName.Name, SurrogateDataAnnotationName.Namespace, knownTypes, Int32.MaxValue, false /*ignoreExtensionDataObject*/, true /*preserveObjectReferences*/, null /*dataContractSurrogate*/); serializer.WriteObject(xmlWriter, surrogateData); xmlWriter.Flush(); return (XmlElement)XmlDoc.ReadNode(XmlReader.Create(new StringReader(stringWriter.ToString()))); } void ExportCollectionDataContract(CollectionDataContract collectionDataContract, XmlSchema schema) { XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = collectionDataContract.StableName.Name; schema.Items.Add(type); XmlElement genericInfoElement = null, isDictionaryElement = null; if (collectionDataContract.UnderlyingType.IsGenericType && CollectionDataContract.IsCollectionDataContract(collectionDataContract.UnderlyingType)) genericInfoElement = ExportGenericInfo(collectionDataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); if (collectionDataContract.IsDictionary) isDictionaryElement = ExportIsDictionary(); type.Annotation = GetSchemaAnnotation(isDictionaryElement, genericInfoElement, ExportSurrogateData(collectionDataContract)); XmlSchemaSequence rootSequence = new XmlSchemaSequence(); XmlSchemaElement element = new XmlSchemaElement(); element.Name = collectionDataContract.ItemName; element.MinOccurs = 0; element.MaxOccursString = Globals.OccursUnbounded; if (collectionDataContract.IsDictionary) { ClassDataContract keyValueContract = collectionDataContract.ItemContract as ClassDataContract; XmlSchemaComplexType keyValueType = new XmlSchemaComplexType(); XmlSchemaSequence keyValueSequence = new XmlSchemaSequence(); foreach (DataMember dataMember in keyValueContract.Members) { XmlSchemaElement keyValueElement = new XmlSchemaElement(); keyValueElement.Name = dataMember.Name; SetElementType(keyValueElement, dataContractSet.GetMemberTypeDataContract(dataMember), schema); SchemaHelper.AddElementForm(keyValueElement, schema); if (dataMember.IsNullable) keyValueElement.IsNillable = true; keyValueElement.Annotation = GetSchemaAnnotation(ExportSurrogateData(dataMember)); keyValueSequence.Items.Add(keyValueElement); } keyValueType.Particle = keyValueSequence; element.SchemaType = keyValueType; } else { if (collectionDataContract.IsItemTypeNullable) element.IsNillable = true; DataContract itemContract = dataContractSet.GetItemTypeDataContract(collectionDataContract); SetElementType(element, itemContract, schema); } SchemaHelper.AddElementForm(element, schema); rootSequence.Items.Add(element); type.Particle = rootSequence; if (collectionDataContract.IsReference) AddReferenceAttributes(type.Attributes, schema); } XmlElement ExportIsDictionary() { XmlElement isDictionaryElement = XmlDoc.CreateElement(IsDictionaryAnnotationName.Name, IsDictionaryAnnotationName.Namespace); isDictionaryElement.InnerText = Globals.True; return isDictionaryElement; } void ExportEnumDataContract(EnumDataContract enumDataContract, XmlSchema schema) { XmlSchemaSimpleType type = new XmlSchemaSimpleType(); type.Name = enumDataContract.StableName.Name; XmlElement actualTypeElement = (enumDataContract.BaseContractName == DefaultEnumBaseTypeName) ? null : ExportActualType(enumDataContract.BaseContractName); type.Annotation = GetSchemaAnnotation(actualTypeElement, ExportSurrogateData(enumDataContract)); schema.Items.Add(type); XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); restriction.BaseTypeName = StringQualifiedName; SchemaHelper.AddSchemaImport(enumDataContract.BaseContractName.Namespace, schema); if (enumDataContract.Values != null) { for (int i = 0; i < enumDataContract.Values.Count; i++) { XmlSchemaEnumerationFacet facet = new XmlSchemaEnumerationFacet(); facet.Value = enumDataContract.Members[i].Name; if (enumDataContract.Values[i] != GetDefaultEnumValue(enumDataContract.IsFlags, i)) facet.Annotation = GetSchemaAnnotation(EnumerationValueAnnotationName, enumDataContract.GetStringFromEnumValue(enumDataContract.Values[i]), schema); restriction.Facets.Add(facet); } } if (enumDataContract.IsFlags) { XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList(); XmlSchemaSimpleType anonymousType = new XmlSchemaSimpleType(); anonymousType.Content = restriction; list.ItemType = anonymousType; type.Content = list; } else type.Content = restriction; } internal static long GetDefaultEnumValue(bool isFlags, int index) { return isFlags ? (long)Math.Pow(2, index) : index; } void ExportISerializableDataContract(ClassDataContract dataContract, XmlSchema schema) { XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = dataContract.StableName.Name; schema.Items.Add(type); XmlElement genericInfoElement = null; if (dataContract.UnderlyingType.IsGenericType) genericInfoElement = ExportGenericInfo(dataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); XmlElement isValueTypeElement = null; if (dataContract.BaseContract != null) { XmlSchemaComplexContentExtension extension = CreateTypeContent(type, dataContract.BaseContract.StableName, schema); } else { schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); type.Particle = ISerializableSequence; XmlSchemaAttribute iSerializableFactoryTypeAttribute = ISerializableFactoryTypeAttribute; type.Attributes.Add(iSerializableFactoryTypeAttribute); SchemaHelper.AddSchemaImport(ISerializableFactoryTypeAttribute.RefName.Namespace, schema); if (dataContract.IsValueType) isValueTypeElement = GetAnnotationMarkup(IsValueTypeName, XmlConvert.ToString(dataContract.IsValueType), schema); } type.Annotation = GetSchemaAnnotation(genericInfoElement, ExportSurrogateData(dataContract), isValueTypeElement); } XmlSchemaComplexContentExtension CreateTypeContent(XmlSchemaComplexType type, XmlQualifiedName baseTypeName, XmlSchema schema) { SchemaHelper.AddSchemaImport(baseTypeName.Namespace, schema); XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension(); extension.BaseTypeName = baseTypeName; type.ContentModel = new XmlSchemaComplexContent(); type.ContentModel.Content = extension; return extension; } void ExportXmlDataContract(XmlDataContract dataContract) { XmlQualifiedName typeQName; bool hasRoot; XmlSchemaType xsdType; Type clrType = dataContract.UnderlyingType; if (!IsSpecialXmlType(clrType, out typeQName, out xsdType, out hasRoot)) if (!InvokeSchemaProviderMethod(clrType, schemas, out typeQName, out xsdType, out hasRoot)) InvokeGetSchemaMethod(clrType, schemas, typeQName); if (hasRoot) { if (!(typeQName.Equals(dataContract.StableName))) { Fx.Assert("XML data contract type name does not match schema name"); } XmlSchema schema; if (SchemaHelper.GetSchemaElement(Schemas, new XmlQualifiedName(dataContract.TopLevelElementName.Value, dataContract.TopLevelElementNamespace.Value), out schema) == null) { XmlSchemaElement topLevelElement = ExportTopLevelElement(dataContract, schema); topLevelElement.IsNillable = dataContract.IsTopLevelElementNullable; ReprocessAll(schemas); } XmlSchemaType anonymousType = xsdType; xsdType = SchemaHelper.GetSchemaType(schemas, typeQName, out schema); if (anonymousType == null && xsdType == null && typeQName.Namespace != XmlSchema.Namespace) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.MissingSchemaType, typeQName, DataContract.GetClrTypeFullName(clrType)))); } if (xsdType != null) xsdType.Annotation = GetSchemaAnnotation( ExportSurrogateData(dataContract), dataContract.IsValueType ? GetAnnotationMarkup(IsValueTypeName, XmlConvert.ToString(dataContract.IsValueType), schema) : null ); else if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.Trace(TraceEventType.Verbose, TraceCode.XsdExportAnnotationFailed, SR.GetString(SR.TraceCodeXsdExportAnnotationFailed), new StringTraceRecord("Type", typeQName.Namespace + ":" + typeQName.Name)); } } } static void ReprocessAll(XmlSchemaSet schemas)// and remove duplicate items { Hashtable elements = new Hashtable(); Hashtable types = new Hashtable(); XmlSchema[] schemaArray = new XmlSchema[schemas.Count]; schemas.CopyTo(schemaArray, 0); for (int i = 0; i < schemaArray.Length; i++) { XmlSchema schema = schemaArray[i]; XmlSchemaObject[] itemArray = new XmlSchemaObject[schema.Items.Count]; schema.Items.CopyTo(itemArray, 0); for (int j = 0; j < itemArray.Length; j++) { XmlSchemaObject item = itemArray[j]; Hashtable items; XmlQualifiedName qname; if (item is XmlSchemaElement) { items = elements; qname = new XmlQualifiedName(((XmlSchemaElement)item).Name, schema.TargetNamespace); } else if (item is XmlSchemaType) { items = types; qname = new XmlQualifiedName(((XmlSchemaType)item).Name, schema.TargetNamespace); } else continue; object otherItem = items[qname]; if (otherItem != null) { if (DiagnosticUtility.ShouldTraceWarning) { Dictionary values = new Dictionary(2) { { "ItemType", item.ToString() }, { "Name", qname.Namespace + ":" + qname.Name } }; TraceUtility.Trace(TraceEventType.Warning, TraceCode.XsdExportDupItems, SR.GetString(SR.TraceCodeXsdExportDupItems), new DictionaryTraceRecord(values)); } schema.Items.Remove(item); } else items.Add(qname, item); } schemas.Reprocess(schema); } } internal static void GetXmlTypeInfo(Type type, out XmlQualifiedName stableName, out XmlSchemaType xsdType, out bool hasRoot) { if (IsSpecialXmlType(type, out stableName, out xsdType, out hasRoot)) return; XmlSchemaSet schemas = new XmlSchemaSet(); schemas.XmlResolver = null; InvokeSchemaProviderMethod(type, schemas, out stableName, out xsdType, out hasRoot); if (stableName.Name == null || stableName.Name.Length == 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidXmlDataContractName, DataContract.GetClrTypeFullName(type)))); } static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schemas, out XmlQualifiedName stableName, out XmlSchemaType xsdType, out bool hasRoot) { xsdType = null; hasRoot = true; object[] attrs = clrType.GetCustomAttributes(Globals.TypeOfXmlSchemaProviderAttribute, false); if (attrs == null || attrs.Length == 0) { stableName = DataContract.GetDefaultStableName(clrType); return false; } XmlSchemaProviderAttribute provider = (XmlSchemaProviderAttribute)attrs[0]; if (provider.IsAny) { xsdType = CreateAnyElementType(); hasRoot = false; } string methodName = provider.MethodName; if (methodName == null || methodName.Length == 0) { if (!provider.IsAny) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidGetSchemaMethod, DataContract.GetClrTypeFullName(clrType)))); stableName = DataContract.GetDefaultStableName(clrType); } else { MethodInfo getMethod = clrType.GetMethod(methodName, /*BindingFlags.DeclaredOnly |*/ BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { typeof(XmlSchemaSet) }, null); if (getMethod == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.MissingGetSchemaMethod, DataContract.GetClrTypeFullName(clrType), methodName))); if (!(Globals.TypeOfXmlQualifiedName.IsAssignableFrom(getMethod.ReturnType)) && !(Globals.TypeOfXmlSchemaType.IsAssignableFrom(getMethod.ReturnType))) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidReturnTypeOnGetSchemaMethod, DataContract.GetClrTypeFullName(clrType), methodName, DataContract.GetClrTypeFullName(getMethod.ReturnType), DataContract.GetClrTypeFullName(Globals.TypeOfXmlQualifiedName), typeof(XmlSchemaType)))); object typeInfo = getMethod.Invoke(null, new object[] { schemas }); if (provider.IsAny) { if (typeInfo != null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidNonNullReturnValueByIsAny, DataContract.GetClrTypeFullName(clrType), methodName))); stableName = DataContract.GetDefaultStableName(clrType); } else if (typeInfo == null) { xsdType = CreateAnyElementType(); hasRoot = false; stableName = DataContract.GetDefaultStableName(clrType); } else { XmlSchemaType providerXsdType = typeInfo as XmlSchemaType; if (providerXsdType != null) { string typeName = providerXsdType.Name; string typeNs = null; if (typeName == null || typeName.Length == 0) { DataContract.GetDefaultStableName(DataContract.GetClrTypeFullName(clrType), out typeName, out typeNs); stableName = new XmlQualifiedName(typeName, typeNs); providerXsdType.Annotation = GetSchemaAnnotation(ExportActualType(stableName, new XmlDocument())); xsdType = providerXsdType; } else { foreach (XmlSchema schema in schemas.Schemas()) { foreach (XmlSchemaObject schemaItem in schema.Items) { if ((object)schemaItem == (object)providerXsdType) { typeNs = schema.TargetNamespace; if (typeNs == null) typeNs = String.Empty; break; } } if (typeNs != null) break; } if (typeNs == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.MissingSchemaType, typeName, DataContract.GetClrTypeFullName(clrType)))); stableName = new XmlQualifiedName(typeName, typeNs); } } else stableName = (XmlQualifiedName)typeInfo; } } return true; } static void InvokeGetSchemaMethod(Type clrType, XmlSchemaSet schemas, XmlQualifiedName stableName) { IXmlSerializable ixmlSerializable = (IXmlSerializable)Activator.CreateInstance(clrType); XmlSchema schema = ixmlSerializable.GetSchema(); if (schema == null) { AddDefaultDatasetType(schemas, stableName.Name, stableName.Namespace); } else { if (schema.Id == null || schema.Id.Length == 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidReturnSchemaOnGetSchemaMethod, DataContract.GetClrTypeFullName(clrType)))); AddDefaultTypedDatasetType(schemas, schema, stableName.Name, stableName.Namespace); } } internal static void AddDefaultXmlType(XmlSchemaSet schemas, string localName, string ns) { XmlSchemaComplexType defaultXmlType = CreateAnyType(); defaultXmlType.Name = localName; XmlSchema schema = SchemaHelper.GetSchema(ns, schemas); schema.Items.Add(defaultXmlType); schemas.Reprocess(schema); } static XmlSchemaComplexType CreateAnyType() { XmlSchemaComplexType anyType = new XmlSchemaComplexType(); anyType.IsMixed = true; anyType.Particle = new XmlSchemaSequence(); XmlSchemaAny any = new XmlSchemaAny(); any.MinOccurs = 0; any.MaxOccurs = Decimal.MaxValue; any.ProcessContents = XmlSchemaContentProcessing.Lax; ((XmlSchemaSequence)anyType.Particle).Items.Add(any); anyType.AnyAttribute = new XmlSchemaAnyAttribute(); return anyType; } static XmlSchemaComplexType CreateAnyElementType() { XmlSchemaComplexType anyElementType = new XmlSchemaComplexType(); anyElementType.IsMixed = false; anyElementType.Particle = new XmlSchemaSequence(); XmlSchemaAny any = new XmlSchemaAny(); any.MinOccurs = 0; any.ProcessContents = XmlSchemaContentProcessing.Lax; ((XmlSchemaSequence)anyElementType.Particle).Items.Add(any); return anyElementType; } internal static bool IsSpecialXmlType(Type type, out XmlQualifiedName typeName, out XmlSchemaType xsdType, out bool hasRoot) { xsdType = null; hasRoot = true; if (type == Globals.TypeOfXmlElement || type == Globals.TypeOfXmlNodeArray) { string name = null; if (type == Globals.TypeOfXmlElement) { xsdType = CreateAnyElementType(); name = "XmlElement"; hasRoot = false; } else { xsdType = CreateAnyType(); name = "ArrayOfXmlNode"; hasRoot = true; } typeName = new XmlQualifiedName(name, DataContract.GetDefaultStableNamespace(type)); return true; } typeName = null; return false; } static void AddDefaultDatasetType(XmlSchemaSet schemas, string localName, string ns) { XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = localName; type.Particle = new XmlSchemaSequence(); XmlSchemaElement schemaRefElement = new XmlSchemaElement(); schemaRefElement.RefName = new XmlQualifiedName(Globals.SchemaLocalName, XmlSchema.Namespace); ((XmlSchemaSequence)type.Particle).Items.Add(schemaRefElement); XmlSchemaAny any = new XmlSchemaAny(); ((XmlSchemaSequence)type.Particle).Items.Add(any); XmlSchema schema = SchemaHelper.GetSchema(ns, schemas); schema.Items.Add(type); schemas.Reprocess(schema); } static void AddDefaultTypedDatasetType(XmlSchemaSet schemas, XmlSchema datasetSchema, string localName, string ns) { XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = localName; type.Particle = new XmlSchemaSequence(); XmlSchemaAny any = new XmlSchemaAny(); any.Namespace = (datasetSchema.TargetNamespace == null) ? String.Empty : datasetSchema.TargetNamespace; ((XmlSchemaSequence)type.Particle).Items.Add(any); schemas.Add(datasetSchema); XmlSchema schema = SchemaHelper.GetSchema(ns, schemas); schema.Items.Add(type); schemas.Reprocess(datasetSchema); schemas.Reprocess(schema); } XmlSchemaAnnotation GetSchemaAnnotation(XmlQualifiedName annotationQualifiedName, string innerText, XmlSchema schema) { XmlSchemaAnnotation annotation = new XmlSchemaAnnotation(); XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo(); XmlElement annotationElement = GetAnnotationMarkup(annotationQualifiedName, innerText, schema); appInfo.Markup = new XmlNode[1] { annotationElement }; annotation.Items.Add(appInfo); return annotation; } static XmlSchemaAnnotation GetSchemaAnnotation(params XmlNode[] nodes) { if (nodes == null || nodes.Length == 0) return null; bool hasAnnotation = false; for (int i = 0; i < nodes.Length; i++) if (nodes[i] != null) { hasAnnotation = true; break; } if (!hasAnnotation) return null; XmlSchemaAnnotation annotation = new XmlSchemaAnnotation(); XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo(); annotation.Items.Add(appInfo); appInfo.Markup = nodes; return annotation; } XmlElement GetAnnotationMarkup(XmlQualifiedName annotationQualifiedName, string innerText, XmlSchema schema) { XmlElement annotationElement = XmlDoc.CreateElement(annotationQualifiedName.Name, annotationQualifiedName.Namespace); SchemaHelper.AddSchemaImport(annotationQualifiedName.Namespace, schema); annotationElement.InnerText = innerText; return annotationElement; } XmlSchema GetSchema(string ns) { return SchemaHelper.GetSchema(ns, Schemas); } // Property is not stored in a local because XmlSchemaSequence is mutable. // The schema export process should not expose objects that may be modified later. internal static XmlSchemaSequence ISerializableSequence { get { XmlSchemaSequence iSerializableSequence = new XmlSchemaSequence(); iSerializableSequence.Items.Add(ISerializableWildcardElement); return iSerializableSequence; } } // Property is not stored in a local because XmlSchemaAny is mutable. // The schema export process should not expose objects that may be modified later. internal static XmlSchemaAny ISerializableWildcardElement { get { XmlSchemaAny iSerializableWildcardElement = new XmlSchemaAny(); iSerializableWildcardElement.MinOccurs = 0; iSerializableWildcardElement.MaxOccursString = Globals.OccursUnbounded; iSerializableWildcardElement.Namespace = "##local"; iSerializableWildcardElement.ProcessContents = XmlSchemaContentProcessing.Skip; return iSerializableWildcardElement; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName anytypeQualifiedName; internal static XmlQualifiedName AnytypeQualifiedName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical anytypeQualifiedName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (anytypeQualifiedName == null) anytypeQualifiedName = new XmlQualifiedName(Globals.AnyTypeLocalName, Globals.SchemaNamespace); return anytypeQualifiedName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName stringQualifiedName; internal static XmlQualifiedName StringQualifiedName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical stringQualifiedName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (stringQualifiedName == null) stringQualifiedName = new XmlQualifiedName(Globals.StringLocalName, Globals.SchemaNamespace); return stringQualifiedName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName defaultEnumBaseTypeName; internal static XmlQualifiedName DefaultEnumBaseTypeName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical defaultEnumBaseTypeName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (defaultEnumBaseTypeName == null) defaultEnumBaseTypeName = new XmlQualifiedName(Globals.IntLocalName, Globals.SchemaNamespace); return defaultEnumBaseTypeName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName enumerationValueAnnotationName; internal static XmlQualifiedName EnumerationValueAnnotationName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical enumerationValueAnnotationName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (enumerationValueAnnotationName == null) enumerationValueAnnotationName = new XmlQualifiedName(Globals.EnumerationValueLocalName, Globals.SerializationNamespace); return enumerationValueAnnotationName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName surrogateDataAnnotationName; internal static XmlQualifiedName SurrogateDataAnnotationName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical surrogateDataAnnotationName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (surrogateDataAnnotationName == null) surrogateDataAnnotationName = new XmlQualifiedName(Globals.SurrogateDataLocalName, Globals.SerializationNamespace); return surrogateDataAnnotationName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName defaultValueAnnotation; internal static XmlQualifiedName DefaultValueAnnotation { [Fx.Tag.SecurityNote(Critical = "Fetches the critical defaultValueAnnotation field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (defaultValueAnnotation == null) defaultValueAnnotation = new XmlQualifiedName(Globals.DefaultValueLocalName, Globals.SerializationNamespace); return defaultValueAnnotation; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName actualTypeAnnotationName; internal static XmlQualifiedName ActualTypeAnnotationName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical actualTypeAnnotationName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (actualTypeAnnotationName == null) actualTypeAnnotationName = new XmlQualifiedName(Globals.ActualTypeLocalName, Globals.SerializationNamespace); return actualTypeAnnotationName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName isDictionaryAnnotationName; internal static XmlQualifiedName IsDictionaryAnnotationName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical isDictionaryAnnotationName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (isDictionaryAnnotationName == null) isDictionaryAnnotationName = new XmlQualifiedName(Globals.IsDictionaryLocalName, Globals.SerializationNamespace); return isDictionaryAnnotationName; } } [Fx.Tag.SecurityNote(Critical = "Static fields are marked SecurityCritical or readonly to prevent" + " data from being modified or leaked to other components in appdomain.")] [SecurityCritical] static XmlQualifiedName isValueTypeName; internal static XmlQualifiedName IsValueTypeName { [Fx.Tag.SecurityNote(Critical = "Fetches the critical isValueTypeName field.", Safe = "Get-only properties only needs to be protected for write; initialized in getter if null.")] [SecuritySafeCritical] get { if (isValueTypeName == null) isValueTypeName = new XmlQualifiedName(Globals.IsValueTypeLocalName, Globals.SerializationNamespace); return isValueTypeName; } } // Property is not stored in a local because XmlSchemaAttribute is mutable. // The schema export process should not expose objects that may be modified later. internal static XmlSchemaAttribute ISerializableFactoryTypeAttribute { get { XmlSchemaAttribute iSerializableFactoryTypeAttribute = new XmlSchemaAttribute(); iSerializableFactoryTypeAttribute.RefName = new XmlQualifiedName(Globals.ISerializableFactoryTypeLocalName, Globals.SerializationNamespace); return iSerializableFactoryTypeAttribute; } } // Property is not stored in a local because XmlSchemaAttribute is mutable. // The schema export process should not expose objects that may be modified later. internal static XmlSchemaAttribute RefAttribute { get { XmlSchemaAttribute refAttribute = new XmlSchemaAttribute(); refAttribute.RefName = Globals.RefQualifiedName; return refAttribute; } } // Property is not stored in a local because XmlSchemaAttribute is mutable. // The schema export process should not expose objects that may be modified later. internal static XmlSchemaAttribute IdAttribute { get { XmlSchemaAttribute idAttribute = new XmlSchemaAttribute(); idAttribute.RefName = Globals.IdQualifiedName; return idAttribute; } } } }