The Labs \ Source Viewer \ SSCLI \ System.Xml.Serialization \ SoapReflectionImporter

  1. //------------------------------------------------------------------------------
  2. // <copyright file="SoapReflectionImporter.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">ElenaK</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Serialization
  17. {
  18.    
  19.     using System.Reflection;
  20.     using System;
  21.     using System.Globalization;
  22.     using System.Xml.Schema;
  23.     using System.Collections;
  24.     using System.ComponentModel;
  25.     using System.Threading;
  26.    
  27.     /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter"]/*' />
  28.     /// <devdoc>
  29.     /// <para>[To be supplied.]</para>
  30.     /// </devdoc>
  31.     public class SoapReflectionImporter
  32.     {
  33.         TypeScope typeScope;
  34.         SoapAttributeOverrides attributeOverrides;
  35.         NameTable types = new NameTable();
  36.         // xmltypename + xmlns -> Mapping
  37.         StructMapping root;
  38.         string defaultNs;
  39.         ModelScope modelScope;
  40.        
  41.        
  42.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.SoapReflectionImporter"]/*' />
  43.         /// <devdoc>
  44.         /// <para>[To be supplied.]</para>
  45.         /// </devdoc>
  46.         public SoapReflectionImporter() : this(null, null)
  47.         {
  48.         }
  49.        
  50.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.SoapReflectionImporter1"]/*' />
  51.         /// <devdoc>
  52.         /// <para>[To be supplied.]</para>
  53.         /// </devdoc>
  54.         public SoapReflectionImporter(string defaultNamespace) : this(null, defaultNamespace)
  55.         {
  56.         }
  57.        
  58.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.SoapReflectionImporter2"]/*' />
  59.         /// <devdoc>
  60.         /// <para>[To be supplied.]</para>
  61.         /// </devdoc>
  62.         public SoapReflectionImporter(SoapAttributeOverrides attributeOverrides) : this(attributeOverrides, null)
  63.         {
  64.         }
  65.        
  66.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.SoapReflectionImporter3"]/*' />
  67.         /// <devdoc>
  68.         /// <para>[To be supplied.]</para>
  69.         /// </devdoc>
  70.         public SoapReflectionImporter(SoapAttributeOverrides attributeOverrides, string defaultNamespace)
  71.         {
  72.             if (defaultNamespace == null)
  73.                 defaultNamespace = String.Empty;
  74.             if (attributeOverrides == null)
  75.                 attributeOverrides = new SoapAttributeOverrides();
  76.             this.attributeOverrides = attributeOverrides;
  77.             this.defaultNs = defaultNamespace;
  78.             this.typeScope = new TypeScope();
  79.             this.modelScope = new ModelScope(this.typeScope);
  80.         }
  81.        
  82.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.IncludeTypes"]/*' />
  83.         /// <devdoc>
  84.         /// <para>[To be supplied.]</para>
  85.         /// </devdoc>
  86.         public void IncludeTypes(ICustomAttributeProvider provider)
  87.         {
  88.             object[] attrs = provider.GetCustomAttributes(typeof(SoapIncludeAttribute), false);
  89.             for (int i = 0; i < attrs.Length; i++) {
  90.                 IncludeType(((SoapIncludeAttribute)attrs[i]).Type);
  91.             }
  92.         }
  93.        
  94.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.IncludeType"]/*' />
  95.         /// <devdoc>
  96.         /// <para>[To be supplied.]</para>
  97.         /// </devdoc>
  98.         public void IncludeType(Type type)
  99.         {
  100.             ImportTypeMapping(modelScope.GetTypeModel(type));
  101.         }
  102.        
  103.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping"]/*' />
  104.         /// <devdoc>
  105.         /// <para>[To be supplied.]</para>
  106.         /// </devdoc>
  107.         public XmlTypeMapping ImportTypeMapping(Type type)
  108.         {
  109.             return ImportTypeMapping(type, null);
  110.         }
  111.        
  112.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping1"]/*' />
  113.         /// <devdoc>
  114.         /// <para>[To be supplied.]</para>
  115.         /// </devdoc>
  116.         public XmlTypeMapping ImportTypeMapping(Type type, string defaultNamespace)
  117.         {
  118.             ElementAccessor element = new ElementAccessor();
  119.             element.IsSoap = true;
  120.             element.Mapping = ImportTypeMapping(modelScope.GetTypeModel(type));
  121.             element.Name = element.Mapping.DefaultElementName;
  122.             element.Namespace = element.Mapping.Namespace == null ? defaultNamespace : element.Mapping.Namespace;
  123.             element.Form = XmlSchemaForm.Qualified;
  124.             XmlTypeMapping xmlMapping = new XmlTypeMapping(typeScope, element);
  125.             xmlMapping.SetKeyInternal(XmlMapping.GenerateKey(type, null, defaultNamespace));
  126.             xmlMapping.IsSoap = true;
  127.             xmlMapping.GenerateSerializer = true;
  128.             return xmlMapping;
  129.         }
  130.        
  131.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.ImportMembersMapping"]/*' />
  132.         /// <devdoc>
  133.         /// <para>[To be supplied.]</para>
  134.         /// </devdoc>
  135.         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members)
  136.         {
  137.             return ImportMembersMapping(elementName, ns, members, true, true, false);
  138.         }
  139.        
  140.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.ImportMembersMapping1"]/*' />
  141.         /// <devdoc>
  142.         /// <para>[To be supplied.]</para>
  143.         /// </devdoc>
  144.         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool writeAccessors)
  145.         {
  146.             return ImportMembersMapping(elementName, ns, members, hasWrapperElement, writeAccessors, false);
  147.         }
  148.        
  149.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.ImportMembersMapping2"]/*' />
  150.         /// <devdoc>
  151.         /// <para>[To be supplied.]</para>
  152.         /// </devdoc>
  153.         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool writeAccessors, bool validate)
  154.         {
  155.             return ImportMembersMapping(elementName, ns, members, hasWrapperElement, writeAccessors, validate, XmlMappingAccess.Read | XmlMappingAccess.Write);
  156.         }
  157.         /// <include file='doc\SoapReflectionImporter.uex' path='docs/doc[@for="SoapReflectionImporter.ImportMembersMapping3"]/*' />
  158.         /// <devdoc>
  159.         /// <para>[To be supplied.]</para>
  160.         /// </devdoc>
  161.         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool writeAccessors, bool validate, XmlMappingAccess access)
  162.         {
  163.             ElementAccessor element = new ElementAccessor();
  164.             element.IsSoap = true;
  165.             element.Name = elementName == null || elementName.Length == 0 ? elementName : XmlConvert.EncodeLocalName(elementName);
  166.            
  167.             element.Mapping = ImportMembersMapping(members, ns, hasWrapperElement, writeAccessors, validate);
  168.             element.Mapping.TypeName = elementName;
  169.             element.Namespace = element.Mapping.Namespace == null ? ns : element.Mapping.Namespace;
  170.             element.Form = XmlSchemaForm.Qualified;
  171.             XmlMembersMapping xmlMapping = new XmlMembersMapping(typeScope, element, access);
  172.             xmlMapping.IsSoap = true;
  173.             xmlMapping.GenerateSerializer = true;
  174.             return xmlMapping;
  175.         }
  176.        
  177.         Exception ReflectionException(string context, Exception e)
  178.         {
  179.             return new InvalidOperationException(Res.GetString(Res.XmlReflectionError, context), e);
  180.         }
  181.        
  182.         SoapAttributes GetAttributes(Type type)
  183.         {
  184.             SoapAttributes attrs = attributeOverrides[type];
  185.             if (attrs != null)
  186.                 return attrs;
  187.             return new SoapAttributes(type);
  188.         }
  189.        
  190.         SoapAttributes GetAttributes(MemberInfo memberInfo)
  191.         {
  192.             SoapAttributes attrs = attributeOverrides[memberInfo.DeclaringType, memberInfo.Name];
  193.             if (attrs != null)
  194.                 return attrs;
  195.             return new SoapAttributes(memberInfo);
  196.         }
  197.        
  198.         TypeMapping ImportTypeMapping(TypeModel model)
  199.         {
  200.             return ImportTypeMapping(model, String.Empty);
  201.         }
  202.        
  203.         TypeMapping ImportTypeMapping(TypeModel model, string dataType)
  204.         {
  205.             if (dataType.Length > 0) {
  206.                 if (!model.TypeDesc.IsPrimitive) {
  207.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDataTypeUsage, dataType, "SoapElementAttribute.DataType"));
  208.                 }
  209.                 TypeDesc td = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
  210.                 if (td == null) {
  211.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXsdDataType, dataType, "SoapElementAttribute.DataType", new XmlQualifiedName(dataType, XmlSchema.Namespace).ToString()));
  212.                 }
  213.                 if (model.TypeDesc.FullName != td.FullName) {
  214.                     throw new InvalidOperationException(Res.GetString(Res.XmlDataTypeMismatch, dataType, "SoapElementAttribute.DataType", model.TypeDesc.FullName));
  215.                 }
  216.             }
  217.            
  218.             SoapAttributes a = GetAttributes(model.Type);
  219.            
  220.             if ((a.SoapFlags & ~SoapAttributeFlags.Type) != 0)
  221.                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidTypeAttributes, model.Type.FullName));
  222.            
  223.             switch (model.TypeDesc.Kind) {
  224.                 case TypeKind.Enum:
  225.                     return ImportEnumMapping((EnumModel)model);
  226.                 case TypeKind.Primitive:
  227.                     return ImportPrimitiveMapping((PrimitiveModel)model, dataType);
  228.                 case TypeKind.Array:
  229.                 case TypeKind.Collection:
  230.                 case TypeKind.Enumerable:
  231.                     return ImportArrayLikeMapping((ArrayModel)model);
  232.                 case TypeKind.Root:
  233.                 case TypeKind.Class:
  234.                 case TypeKind.Struct:
  235.                     if (model.TypeDesc.IsOptionalValue) {
  236.                         TypeDesc baseTypeDesc = model.TypeDesc.BaseTypeDesc;
  237.                         SoapAttributes baseAttributes = GetAttributes(baseTypeDesc.Type);
  238.                         string typeNs = defaultNs;
  239.                         if (baseAttributes.SoapType != null && baseAttributes.SoapType.Namespace != null)
  240.                             typeNs = baseAttributes.SoapType.Namespace;
  241.                        
  242.                         TypeMapping baseMapping = GetTypeMapping(baseTypeDesc.Name, typeNs, baseTypeDesc);
  243.                         if (baseMapping == null)
  244.                             baseMapping = ImportTypeMapping(modelScope.GetTypeModel(baseTypeDesc.Type, true), dataType);
  245.                         return CreateNullableMapping(baseMapping, model.TypeDesc);
  246.                     }
  247.                     else {
  248.                         return ImportStructLikeMapping((StructModel)model);
  249.                     }
  250.                     break;
  251.                 default:
  252.                     throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedSoapTypeKind, model.TypeDesc.FullName));
  253.                     break;
  254.             }
  255.         }
  256.        
  257.         StructMapping CreateRootMapping()
  258.         {
  259.             TypeDesc typeDesc = typeScope.GetTypeDesc(typeof(object));
  260.             StructMapping mapping = new StructMapping();
  261.             mapping.IsSoap = true;
  262.             mapping.TypeDesc = typeDesc;
  263.             mapping.Members = new MemberMapping[0];
  264.             mapping.IncludeInSchema = false;
  265.             mapping.TypeName = Soap.UrType;
  266.             mapping.Namespace = XmlSchema.Namespace;
  267.             return mapping;
  268.         }
  269.        
  270.         StructMapping GetRootMapping()
  271.         {
  272.             if (root == null) {
  273.                 root = CreateRootMapping();
  274.                 typeScope.AddTypeMapping(root);
  275.             }
  276.             return root;
  277.         }
  278.        
  279.         TypeMapping GetTypeMapping(string typeName, string ns, TypeDesc typeDesc)
  280.         {
  281.             TypeMapping mapping = (TypeMapping)types[typeName, ns];
  282.             if (mapping == null)
  283.                 return null;
  284.             if (mapping.TypeDesc != typeDesc)
  285.                 throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, mapping.TypeDesc.FullName, typeName, ns));
  286.             return mapping;
  287.         }
  288.        
  289.         NullableMapping CreateNullableMapping(TypeMapping baseMapping, TypeDesc typeDesc)
  290.         {
  291.             TypeMapping existingMapping = (TypeMapping)types[typeDesc.Name, baseMapping.Namespace];
  292.             NullableMapping mapping;
  293.             if (existingMapping != null) {
  294.                 if (existingMapping is NullableMapping) {
  295.                     mapping = (NullableMapping)existingMapping;
  296.                     if (mapping.BaseMapping is PrimitiveMapping && baseMapping is PrimitiveMapping)
  297.                         return mapping;
  298.                     else if (mapping.BaseMapping == baseMapping) {
  299.                         return mapping;
  300.                     }
  301.                     else {
  302.                         throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
  303.                     }
  304.                 }
  305.                 else if (!(baseMapping is PrimitiveMapping)) {
  306.                     throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
  307.                 }
  308.             }
  309.             mapping = new NullableMapping();
  310.             mapping.BaseMapping = baseMapping;
  311.             mapping.TypeDesc = typeDesc;
  312.             mapping.TypeName = baseMapping.TypeName;
  313.             mapping.Namespace = baseMapping.Namespace;
  314.             mapping.IncludeInSchema = false;
  315.             //baseMapping.IncludeInSchema;
  316.             types.Add(typeDesc.Name, baseMapping.Namespace, mapping);
  317.             typeScope.AddTypeMapping(mapping);
  318.             return mapping;
  319.         }
  320.        
  321.         StructMapping ImportStructLikeMapping(StructModel model)
  322.         {
  323.             if (model.TypeDesc.Kind == TypeKind.Root)
  324.                 return GetRootMapping();
  325.            
  326.             SoapAttributes a = GetAttributes(model.Type);
  327.            
  328.             string typeNs = defaultNs;
  329.             if (a.SoapType != null && a.SoapType.Namespace != null)
  330.                 typeNs = a.SoapType.Namespace;
  331.             string typeName = XsdTypeName(model.Type, a, model.TypeDesc.Name);
  332.             typeName = XmlConvert.EncodeLocalName(typeName);
  333.            
  334.             StructMapping mapping = (StructMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc);
  335.             if (mapping == null) {
  336.                 mapping = new StructMapping();
  337.                 mapping.IsSoap = true;
  338.                 mapping.TypeDesc = model.TypeDesc;
  339.                 mapping.Namespace = typeNs;
  340.                 mapping.TypeName = typeName;
  341.                 if (a.SoapType != null)
  342.                     mapping.IncludeInSchema = a.SoapType.IncludeInSchema;
  343.                 typeScope.AddTypeMapping(mapping);
  344.                 types.Add(typeName, typeNs, mapping);
  345.                 if (model.TypeDesc.BaseTypeDesc != null) {
  346.                     mapping.BaseMapping = ImportStructLikeMapping((StructModel)modelScope.GetTypeModel(model.Type.BaseType, false));
  347.                 }
  348.                 ArrayList members = new ArrayList();
  349.                 foreach (MemberInfo memberInfo in model.GetMemberInfos()) {
  350.                     if ((memberInfo.MemberType & (MemberTypes.Field | MemberTypes.Property)) == 0)
  351.                         continue;
  352.                     SoapAttributes memberAttrs = GetAttributes(memberInfo);
  353.                     if (memberAttrs.SoapIgnore)
  354.                         continue;
  355.                     FieldModel fieldModel = model.GetFieldModel(memberInfo);
  356.                     if (fieldModel == null)
  357.                         continue;
  358.                     MemberMapping member = ImportFieldMapping(fieldModel, memberAttrs, mapping.Namespace);
  359.                     if (member == null)
  360.                         continue;
  361.                    
  362.                     if (!member.TypeDesc.IsPrimitive && !member.TypeDesc.IsEnum && !member.TypeDesc.IsOptionalValue) {
  363.                         if (model.TypeDesc.IsValueType)
  364.                             throw new NotSupportedException(Res.GetString(Res.XmlRpcRefsInValueType, model.TypeDesc.FullName));
  365.                         if (member.TypeDesc.IsValueType)
  366.                             throw new NotSupportedException(Res.GetString(Res.XmlRpcNestedValueType, member.TypeDesc.FullName));
  367.                     }
  368.                     if (mapping.BaseMapping != null) {
  369.                         if (mapping.BaseMapping.Declares(member, mapping.TypeName))
  370.                             continue;
  371.                     }
  372.                     members.Add(member);
  373.                 }
  374.                 mapping.Members = (MemberMapping[])members.ToArray(typeof(MemberMapping));
  375.                 if (mapping.BaseMapping == null)
  376.                     mapping.BaseMapping = GetRootMapping();
  377.                 IncludeTypes(model.Type);
  378.             }
  379.             return mapping;
  380.         }
  381.        
  382.         ArrayMapping ImportArrayLikeMapping(ArrayModel model)
  383.         {
  384.            
  385.             ArrayMapping mapping = new ArrayMapping();
  386.             mapping.IsSoap = true;
  387.             TypeMapping itemTypeMapping = ImportTypeMapping(model.Element);
  388.            
  389.             if (itemTypeMapping.TypeDesc.IsValueType && !itemTypeMapping.TypeDesc.IsPrimitive && !itemTypeMapping.TypeDesc.IsEnum)
  390.                 throw new NotSupportedException(Res.GetString(Res.XmlRpcArrayOfValueTypes, model.TypeDesc.FullName));
  391.            
  392.             mapping.TypeDesc = model.TypeDesc;
  393.             mapping.Elements = new ElementAccessor[] {CreateElementAccessor(itemTypeMapping, mapping.Namespace)};
  394.             SetArrayMappingType(mapping);
  395.            
  396.             // in the case of an ArrayMapping we can have more that one mapping correspond to a type
  397.             // examples of that are ArrayList and object[] both will map tp ArrayOfur-type
  398.             // so we create a link list for all mappings of the same XSD type
  399.             ArrayMapping existingMapping = (ArrayMapping)types[mapping.TypeName, mapping.Namespace];
  400.             if (existingMapping != null) {
  401.                 ArrayMapping first = existingMapping;
  402.                 while (existingMapping != null) {
  403.                     if (existingMapping.TypeDesc == model.TypeDesc)
  404.                         return existingMapping;
  405.                     existingMapping = existingMapping.Next;
  406.                 }
  407.                 mapping.Next = first;
  408.                 types[mapping.TypeName, mapping.Namespace] = mapping;
  409.                 return mapping;
  410.             }
  411.             typeScope.AddTypeMapping(mapping);
  412.             types.Add(mapping.TypeName, mapping.Namespace, mapping);
  413.             IncludeTypes(model.Type);
  414.             return mapping;
  415.         }
  416.        
  417.         void SetArrayMappingType(ArrayMapping mapping)
  418.         {
  419.             bool useDefaultNs = false;
  420.            
  421.             string itemTypeName;
  422.             string itemTypeNamespace;
  423.            
  424.             TypeMapping itemTypeMapping;
  425.             if (mapping.Elements.Length == 1)
  426.                 itemTypeMapping = mapping.Elements[0].Mapping;
  427.             else
  428.                 itemTypeMapping = null;
  429.            
  430.             if (itemTypeMapping is EnumMapping) {
  431.                 itemTypeNamespace = itemTypeMapping.Namespace;
  432.                 itemTypeName = itemTypeMapping.TypeName;
  433.             }
  434.             else if (itemTypeMapping is PrimitiveMapping) {
  435.                 itemTypeNamespace = itemTypeMapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : UrtTypes.Namespace;
  436.                 itemTypeName = itemTypeMapping.TypeDesc.DataType.Name;
  437.                 useDefaultNs = true;
  438.             }
  439.             else if (itemTypeMapping is StructMapping) {
  440.                 if (itemTypeMapping.TypeDesc.IsRoot) {
  441.                     itemTypeNamespace = XmlSchema.Namespace;
  442.                     itemTypeName = Soap.UrType;
  443.                     useDefaultNs = true;
  444.                 }
  445.                 else {
  446.                     itemTypeNamespace = itemTypeMapping.Namespace;
  447.                     itemTypeName = itemTypeMapping.TypeName;
  448.                 }
  449.             }
  450.             else if (itemTypeMapping is ArrayMapping) {
  451.                 itemTypeNamespace = itemTypeMapping.Namespace;
  452.                 itemTypeName = itemTypeMapping.TypeName;
  453.             }
  454.             else {
  455.                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidSoapArray, mapping.TypeDesc.FullName));
  456.             }
  457.            
  458.             itemTypeName = CodeIdentifier.MakePascal(itemTypeName);
  459.             string uniqueName = "ArrayOf" + itemTypeName;
  460.             string ns = useDefaultNs ? defaultNs : itemTypeNamespace;
  461.             int i = 1;
  462.             TypeMapping existingMapping = (TypeMapping)types[uniqueName, ns];
  463.             while (existingMapping != null) {
  464.                 if (existingMapping is ArrayMapping) {
  465.                     ArrayMapping arrayMapping = (ArrayMapping)existingMapping;
  466.                     if (AccessorMapping.ElementsMatch(arrayMapping.Elements, mapping.Elements)) {
  467.                         break;
  468.                     }
  469.                 }
  470.                 // need to re-name the mapping
  471.                 uniqueName = itemTypeName + i.ToString(CultureInfo.InvariantCulture);
  472.                 existingMapping = (TypeMapping)types[uniqueName, ns];
  473.                 i++;
  474.             }
  475.             mapping.Namespace = ns;
  476.             mapping.TypeName = uniqueName;
  477.         }
  478.        
  479.         PrimitiveMapping ImportPrimitiveMapping(PrimitiveModel model, string dataType)
  480.         {
  481.             PrimitiveMapping mapping = new PrimitiveMapping();
  482.             mapping.IsSoap = true;
  483.             if (dataType.Length > 0) {
  484.                 mapping.TypeDesc = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
  485.                 if (mapping.TypeDesc == null) {
  486.                     // try it as a non-Xsd type
  487.                     mapping.TypeDesc = typeScope.GetTypeDesc(dataType, UrtTypes.Namespace);
  488.                     if (mapping.TypeDesc == null) {
  489.                         throw new InvalidOperationException(Res.GetString(Res.XmlUdeclaredXsdType, dataType));
  490.                     }
  491.                 }
  492.             }
  493.             else {
  494.                 mapping.TypeDesc = model.TypeDesc;
  495.             }
  496.             mapping.TypeName = mapping.TypeDesc.DataType.Name;
  497.             mapping.Namespace = mapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : UrtTypes.Namespace;
  498.             return mapping;
  499.         }
  500.        
  501.         EnumMapping ImportEnumMapping(EnumModel model)
  502.         {
  503.             SoapAttributes a = GetAttributes(model.Type);
  504.             string typeNs = defaultNs;
  505.             if (a.SoapType != null && a.SoapType.Namespace != null)
  506.                 typeNs = a.SoapType.Namespace;
  507.             string typeName = XsdTypeName(model.Type, a, model.TypeDesc.Name);
  508.             typeName = XmlConvert.EncodeLocalName(typeName);
  509.            
  510.             EnumMapping mapping = (EnumMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc);
  511.             if (mapping == null) {
  512.                 mapping = new EnumMapping();
  513.                 mapping.IsSoap = true;
  514.                 mapping.TypeDesc = model.TypeDesc;
  515.                 mapping.TypeName = typeName;
  516.                 mapping.Namespace = typeNs;
  517.                 mapping.IsFlags = model.Type.IsDefined(typeof(FlagsAttribute), false);
  518.                 typeScope.AddTypeMapping(mapping);
  519.                 types.Add(typeName, typeNs, mapping);
  520.                 ArrayList constants = new ArrayList();
  521.                 for (int i = 0; i < model.Constants.Length; i++) {
  522.                     ConstantMapping constant = ImportConstantMapping(model.Constants[i]);
  523.                     if (constant != null)
  524.                         constants.Add(constant);
  525.                 }
  526.                 if (constants.Count == 0) {
  527.                     throw new InvalidOperationException(Res.GetString(Res.XmlNoSerializableMembers, model.TypeDesc.FullName));
  528.                 }
  529.                 mapping.Constants = (ConstantMapping[])constants.ToArray(typeof(ConstantMapping));
  530.             }
  531.             return mapping;
  532.         }
  533.        
  534.         ConstantMapping ImportConstantMapping(ConstantModel model)
  535.         {
  536.             SoapAttributes a = GetAttributes(model.FieldInfo);
  537.             if (a.SoapIgnore)
  538.                 return null;
  539.             if ((a.SoapFlags & ~SoapAttributeFlags.Enum) != 0)
  540.                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidEnumAttribute));
  541.             if (a.SoapEnum == null)
  542.                 a.SoapEnum = new SoapEnumAttribute();
  543.            
  544.             ConstantMapping constant = new ConstantMapping();
  545.             constant.XmlName = a.SoapEnum.Name.Length == 0 ? model.Name : a.SoapEnum.Name;
  546.             constant.Name = model.Name;
  547.             constant.Value = model.Value;
  548.             return constant;
  549.         }
  550.        
  551.         MembersMapping ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, string ns, bool hasWrapperElement, bool writeAccessors, bool validateWrapperElement)
  552.         {
  553.             MembersMapping members = new MembersMapping();
  554.             members.TypeDesc = typeScope.GetTypeDesc(typeof(object[]));
  555.             MemberMapping[] mappings = new MemberMapping[xmlReflectionMembers.Length];
  556.             for (int i = 0; i < mappings.Length; i++) {
  557.                 try {
  558.                     XmlReflectionMember member = xmlReflectionMembers[i];
  559.                     MemberMapping mapping = ImportMemberMapping(member, ns, xmlReflectionMembers, hasWrapperElement ? XmlSchemaForm.Unqualified : XmlSchemaForm.Qualified);
  560.                     if (member.IsReturnValue && writeAccessors) {
  561.                         // no special treatment for return values with doc/enc
  562.                         if (i > 0)
  563.                             throw new InvalidOperationException(Res.GetString(Res.XmlInvalidReturnPosition));
  564.                         mapping.IsReturnValue = true;
  565.                     }
  566.                     mappings[i] = mapping;
  567.                 }
  568.                 catch (Exception e) {
  569.                     if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
  570.                         throw;
  571.                     }
  572.                     throw ReflectionException(xmlReflectionMembers[i].MemberName, e);
  573.                 }
  574.                 catch {
  575.                     throw ReflectionException(xmlReflectionMembers[i].MemberName, null);
  576.                 }
  577.             }
  578.             members.Members = mappings;
  579.             members.HasWrapperElement = hasWrapperElement;
  580.             if (hasWrapperElement) {
  581.                 members.ValidateRpcWrapperElement = validateWrapperElement;
  582.             }
  583.             members.WriteAccessors = writeAccessors;
  584.             members.IsSoap = true;
  585.             if (hasWrapperElement && !writeAccessors)
  586.                 members.Namespace = ns;
  587.             return members;
  588.         }
  589.        
  590.         MemberMapping ImportMemberMapping(XmlReflectionMember xmlReflectionMember, string ns, XmlReflectionMember[] xmlReflectionMembers, XmlSchemaForm form)
  591.         {
  592.             SoapAttributes a = xmlReflectionMember.SoapAttributes;
  593.             if (a.SoapIgnore)
  594.                 return null;
  595.             MemberMapping member = new MemberMapping();
  596.             member.IsSoap = true;
  597.             member.Name = xmlReflectionMember.MemberName;
  598.             bool checkSpecified = XmlReflectionImporter.FindSpecifiedMember(xmlReflectionMember.MemberName, xmlReflectionMembers) != null;
  599.             FieldModel model = new FieldModel(xmlReflectionMember.MemberName, xmlReflectionMember.MemberType, typeScope.GetTypeDesc(xmlReflectionMember.MemberType), checkSpecified, false);
  600.             member.CheckShouldPersist = model.CheckShouldPersist;
  601.             member.CheckSpecified = model.CheckSpecified;
  602.             member.ReadOnly = model.ReadOnly;
  603.             // || !model.FieldTypeDesc.HasDefaultConstructor;
  604.             ImportAccessorMapping(member, model, a, ns, form);
  605.             if (xmlReflectionMember.OverrideIsNullable)
  606.                 member.Elements[0].IsNullable = false;
  607.             return member;
  608.         }
  609.        
  610.         MemberMapping ImportFieldMapping(FieldModel model, SoapAttributes a, string ns)
  611.         {
  612.             if (a.SoapIgnore)
  613.                 return null;
  614.             MemberMapping member = new MemberMapping();
  615.             member.IsSoap = true;
  616.             member.Name = model.Name;
  617.             member.CheckShouldPersist = model.CheckShouldPersist;
  618.             member.CheckSpecified = model.CheckSpecified;
  619.             member.ReadOnly = model.ReadOnly;
  620.             // || !model.FieldTypeDesc.HasDefaultConstructor;
  621.             ImportAccessorMapping(member, model, a, ns, XmlSchemaForm.Unqualified);
  622.             return member;
  623.         }
  624.        
  625.         void ImportAccessorMapping(MemberMapping accessor, FieldModel model, SoapAttributes a, string ns, XmlSchemaForm form)
  626.         {
  627.             Type accessorType = model.FieldType;
  628.             string accessorName = model.Name;
  629.             accessor.TypeDesc = typeScope.GetTypeDesc(accessorType);
  630.             if (accessor.TypeDesc.IsVoid) {
  631.                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidVoid));
  632.             }
  633.            
  634.             SoapAttributeFlags flags = a.SoapFlags;
  635.             if ((flags & SoapAttributeFlags.Attribute) == SoapAttributeFlags.Attribute) {
  636.                 if (!accessor.TypeDesc.IsPrimitive && !accessor.TypeDesc.IsEnum)
  637.                     throw new InvalidOperationException(Res.GetString(Res.XmlIllegalSoapAttribute, accessorName, accessor.TypeDesc.FullName));
  638.                
  639.                 if ((flags & SoapAttributeFlags.Attribute) != flags)
  640.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidElementAttribute));
  641.                
  642.                 AttributeAccessor attribute = new AttributeAccessor();
  643.                 attribute.Name = Accessor.EscapeQName(a.SoapAttribute == null || a.SoapAttribute.AttributeName.Length == 0 ? accessorName : a.SoapAttribute.AttributeName);
  644.                 attribute.Namespace = a.SoapAttribute == null || a.SoapAttribute.Namespace == null ? ns : a.SoapAttribute.Namespace;
  645.                 attribute.Form = XmlSchemaForm.Qualified;
  646.                 // attributes are always qualified since they're only used for encoded soap headers
  647.                 attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), (a.SoapAttribute == null ? String.Empty : a.SoapAttribute.DataType));
  648.                 attribute.Default = GetDefaultValue(model.FieldTypeDesc, a);
  649.                 accessor.Attribute = attribute;
  650.                 accessor.Elements = new ElementAccessor[0];
  651.             }
  652.             else {
  653.                 if ((flags & SoapAttributeFlags.Element) != flags)
  654.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidElementAttribute));
  655.                
  656.                 ElementAccessor element = new ElementAccessor();
  657.                 element.IsSoap = true;
  658.                 element.Name = XmlConvert.EncodeLocalName(a.SoapElement == null || a.SoapElement.ElementName.Length == 0 ? accessorName : a.SoapElement.ElementName);
  659.                 element.Namespace = ns;
  660.                 element.Form = form;
  661.                 element.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), (a.SoapElement == null ? String.Empty : a.SoapElement.DataType));
  662.                 if (a.SoapElement != null)
  663.                     element.IsNullable = a.SoapElement.IsNullable;
  664.                 accessor.Elements = new ElementAccessor[] {element};
  665.             }
  666.         }
  667.        
  668.         static ElementAccessor CreateElementAccessor(TypeMapping mapping, string ns)
  669.         {
  670.             ElementAccessor element = new ElementAccessor();
  671.             element.IsSoap = true;
  672.             element.Name = mapping.TypeName;
  673.             //XmlConvert.EncodeLocalName(name == null || name.Length == 0 ? mapping.TypeName : name);
  674.             element.Namespace = ns;
  675.             element.Mapping = mapping;
  676.             return element;
  677.         }
  678.        
  679.         object GetDefaultValue(TypeDesc fieldTypeDesc, SoapAttributes a)
  680.         {
  681.             if (a.SoapDefaultValue == null || a.SoapDefaultValue == DBNull.Value)
  682.                 return null;
  683.             if (!(fieldTypeDesc.Kind == TypeKind.Primitive || fieldTypeDesc.Kind == TypeKind.Enum)) {
  684.                 a.SoapDefaultValue = null;
  685.                 return a.SoapDefaultValue;
  686.             }
  687.             // for enums validate and return a string representation
  688.             if (fieldTypeDesc.Kind == TypeKind.Enum) {
  689.                 if (fieldTypeDesc != typeScope.GetTypeDesc(a.SoapDefaultValue.GetType()))
  690.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultEnumValue, a.SoapDefaultValue.GetType().FullName, fieldTypeDesc.FullName));
  691.                 string strValue = Enum.Format(a.SoapDefaultValue.GetType(), a.SoapDefaultValue, "G").Replace(",", " ");
  692.                 string numValue = Enum.Format(a.SoapDefaultValue.GetType(), a.SoapDefaultValue, "D");
  693.                 if (strValue == numValue)
  694.                     // means enum value wasn't recognized
  695.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, strValue, a.SoapDefaultValue.GetType().FullName));
  696.                 return strValue;
  697.             }
  698.             return a.SoapDefaultValue;
  699.         }
  700.        
  701.         internal string XsdTypeName(Type type)
  702.         {
  703.             if (type == typeof(object))
  704.                 return Soap.UrType;
  705.             TypeDesc typeDesc = typeScope.GetTypeDesc(type);
  706.             if (typeDesc.IsPrimitive && typeDesc.DataType != null && typeDesc.DataType.Name != null && typeDesc.DataType.Name.Length > 0)
  707.                 return typeDesc.DataType.Name;
  708.             return XsdTypeName(type, GetAttributes(type), typeDesc.Name);
  709.         }
  710.         internal string XsdTypeName(Type type, SoapAttributes a, string name)
  711.         {
  712.             string typeName = name;
  713.             if (a.SoapType != null && a.SoapType.TypeName.Length > 0)
  714.                 typeName = a.SoapType.TypeName;
  715.            
  716.             if (type.IsGenericType && typeName.IndexOf('{') >= 0) {
  717.                 Type genType = type.GetGenericTypeDefinition();
  718.                 Type[] names = genType.GetGenericArguments();
  719.                 Type[] types = type.GetGenericArguments();
  720.                
  721.                 for (int i = 0; i < names.Length; i++) {
  722.                     string argument = "{" + names[i] + "}";
  723.                     if (typeName.Contains(argument)) {
  724.                         typeName = typeName.Replace(argument, XsdTypeName(types[i]));
  725.                         if (typeName.IndexOf('{') < 0) {
  726.                             break;
  727.                         }
  728.                     }
  729.                 }
  730.             }
  731.             return typeName;
  732.         }
  733.     }
  734. }

Developer Fusion