|
//------------------------------------------------------------
// 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<XmlQualifiedName, DataContract> 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(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, 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<int> 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<Type> knownTypes = new Collection<Type>();
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<string, string> values = new Dictionary<string, string>(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;
}
}
}
}
|