소스 검색

[WCF,Serialization] Improve and fully implement support for collection types.

* System.Runtime.Serialization/XsdDataContractImporter:
      Check ImportOptions.ReferencedCollectionTypes to determine the proxy type.

* System.ServiceModel.Description/MetadataImporter.cs:
      Very simply implementation of the 'State' property.

* System.ServiceModel.Description/DataContractSerializerMessageContractImporter.cs:
      Use it here.

* Test/Resources/WSDL: Added some sample .wsdl files for the new tests; adding
      these as resources to the test dll.

* Test/System.Runtime.Serialization: Added WsdlHelper.cs,
      XsdDataContractImporterTest2.cs and XsdDataContractExportTest2.cs
Martin Baulig 13 년 전
부모
커밋
ea570f3a76

+ 11 - 6
mcs/class/System.Runtime.Serialization/Makefile

@@ -7,19 +7,24 @@ RESOURCE_FILES = \
 
 
 LIBRARY = System.Runtime.Serialization.dll
 LIBRARY = System.Runtime.Serialization.dll
 LIB_MCS_FLAGS = \
 LIB_MCS_FLAGS = \
-			/nowarn:168,169,219,414 \
-	        /r:System.dll \
-	        /r:System.Xml.dll \
+		/nowarn:168,169,219,414 \
+		/r:System.dll \
+		/r:System.Xml.dll \
 		/r:System.Core.dll \
 		/r:System.Core.dll \
-	        $(RESOURCE_FILES:%=/resource:%)
+		$(RESOURCE_FILES:%=/resource:%)
 
 
 ifneq (2.1, $(FRAMEWORK_VERSION))
 ifneq (2.1, $(FRAMEWORK_VERSION))
 LIB_MCS_FLAGS += /d:NET_3_0 /r:System.Data.dll /r:System.Configuration.dll
 LIB_MCS_FLAGS += /d:NET_3_0 /r:System.Data.dll /r:System.Configuration.dll
 endif
 endif
 
 
-TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) /r:System.ServiceModel.dll
+TEST_RESOURCE_FILES = \
+	Test/Resources/WSDL/collections.wsdl	\
+	Test/Resources/WSDL/custom-collections.wsdl
 
 
-EXTRA_DISTFILES = $(RESOURCE_FILES) \
+TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) /r:System.ServiceModel.dll /r:System.Web.Services.dll \
+	$(TEST_RESOURCE_FILES:%=/resource:%)
+
+EXTRA_DISTFILES = $(RESOURCE_FILES) $(TEST_RESOURCE_FILES) \
 	Test/Resources/FrameworkTypes/* \
 	Test/Resources/FrameworkTypes/* \
 	Test/Resources/Schemas/*.xsd \
 	Test/Resources/Schemas/*.xsd \
 	Test/System.Runtime.Serialization/one.xml
 	Test/System.Runtime.Serialization/one.xml

+ 163 - 19
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XsdDataContractImporter.cs

@@ -1,10 +1,12 @@
 //
 //
 // XsdDataContractImporter.cs
 // XsdDataContractImporter.cs
 //
 //
-// Author:
+// Authors:
 //	Atsushi Enomoto <[email protected]>
 //	Atsushi Enomoto <[email protected]>
+//      Martin Baulig <[email protected]>
 //
 //
 // Copyright (C) 2010 Novell, Inc.  http://www.novell.com
 // Copyright (C) 2010 Novell, Inc.  http://www.novell.com
+//               2012 Xamarin, Inc.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // a copy of this software and associated documentation files (the
@@ -29,6 +31,7 @@
 using System;
 using System;
 using System.CodeDom;
 using System.CodeDom;
 using System.CodeDom.Compiler;
 using System.CodeDom.Compiler;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
@@ -458,6 +461,11 @@ namespace System.Runtime.Serialization
 				return qn;
 				return qn;
 			}
 			}
 
 
+			if (element.ElementSchemaType != null) {
+				if (IsCollectionType (element.ElementSchemaType))
+					elname = element.ElementSchemaType.QualifiedName;
+			}
+
 			// FIXME: use element to fill nillable and arrays.
 			// FIXME: use element to fill nillable and arrays.
 			var qname =
 			var qname =
 				elname != null && !elname.Equals (QName.Empty) ? elname :
 				elname != null && !elname.Equals (QName.Empty) ? elname :
@@ -656,6 +664,43 @@ namespace System.Runtime.Serialization
 			}
 			}
 		}
 		}
 
 
+		// Returns false if it should remove the imported type.
+		bool IsCollectionType (XmlSchemaType type)
+		{
+			var complex = type as XmlSchemaComplexType;
+			if (complex == null)
+				return false;
+
+			var seq = complex.Particle as XmlSchemaSequence;
+			if (seq == null)
+				return false;
+
+			if (seq.Items.Count == 1 && seq.Items [0] is XmlSchemaAny && complex.Parent is XmlSchemaElement)
+				return false;
+
+			if (type.Annotation != null) {
+				foreach (var ann in type.Annotation.Items) {
+					var ai = ann as XmlSchemaAppInfo;
+					if (ai != null && ai.Markup != null &&
+					    ai.Markup.Length > 0 &&
+					    ai.Markup [0].NodeType == XmlNodeType.Element &&
+					    ai.Markup [0].LocalName == "IsDictionary" &&
+					    ai.Markup [0].NamespaceURI == KnownTypeCollection.MSSimpleNamespace)
+						return true;
+				}
+			}
+					
+			if (seq.Items.Count != 1)
+				return false;
+
+			var pt = (XmlSchemaParticle) seq.Items [0];
+			var xe = pt as XmlSchemaElement;
+			if (pt.MaxOccursString != "unbounded")
+				return false;
+
+			return !(pt is XmlSchemaAny);
+		}
+
 		// Returns false if it should remove the imported type.
 		// Returns false if it should remove the imported type.
 		bool ImportComplexType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaComplexType type, XmlQualifiedName qname)
 		bool ImportComplexType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaComplexType type, XmlQualifiedName qname)
 		{
 		{
@@ -721,6 +766,33 @@ namespace System.Runtime.Serialization
 				}
 				}
 			}
 			}
 
 
+			/*
+			 * Collection Type Support:
+			 * 
+			 * We need to distinguish between normal array/dictionary collections and
+			 * custom collection types which use [CollectionDataContract].
+			 * 
+			 * The name of a normal collection type starts with "ArrayOf" and uses the
+			 * element type's namespace.  We use the collection type directly and don't
+			 * generate a proxy class for these.
+			 * 
+			 * The collection type (and the base class or a custom collection's proxy type)
+			 * is dermined by 'ImportOptions.ReferencedCollectionTypes'.  The default is to
+			 * use an array for list collections and Dictionary<,> for dictionaries.
+			 * 
+			 * Note that my implementation currently only checks for generic type definitions
+			 * in the 'ImportOptions.ReferencedCollectionTypes' - it looks for something that
+			 * implements IEnumerable<T> or IDictionary<K,V>.  This is not complete, but it's
+			 * all that's necessary to support different collection types in a GUI.
+			 * 
+			 * Simply use
+			 *     var options = new ImportOptions ();
+			 *     options.ReferencedCollectionTypes.Add (typeof (LinkedList<>));
+			 *     options.ReferencedCollectionTypes.Add (typeof (SortedList<,>));
+			 * to configure these; see XsdDataContractImportTest2.cs for some examples.
+			 * 
+			 */
+
 			if (seq.Items.Count == 1) {
 			if (seq.Items.Count == 1) {
 				var pt = (XmlSchemaParticle) seq.Items [0];
 				var pt = (XmlSchemaParticle) seq.Items [0];
 				var xe = pt as XmlSchemaElement;
 				var xe = pt as XmlSchemaElement;
@@ -734,24 +806,9 @@ namespace System.Runtime.Serialization
 						var v = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [1] as XmlSchemaElement : null;
 						var v = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [1] as XmlSchemaElement : null;
 						if (k == null || v == null)
 						if (k == null || v == null)
 							throw new InvalidDataContractException (String.Format ("Invalid Dictionary contract type '{0}'. A Dictionary schema type must have a sequence particle which contains exactly two schema elements for key and value.", type.QualifiedName));
 							throw new InvalidDataContractException (String.Format ("Invalid Dictionary contract type '{0}'. A Dictionary schema type must have a sequence particle which contains exactly two schema elements for key and value.", type.QualifiedName));
-						Import (schemas, k.ElementSchemaType);
-						Import (schemas, v.ElementSchemaType);
-						td.BaseTypes.Add (new CodeTypeReference ("System.Collections.Generic.Dictionary", GetCodeTypeReference (k.ElementSchemaType.QualifiedName), GetCodeTypeReference (v.ElementSchemaType.QualifiedName)));
-						AddTypeAttributes (td, type, xe, k, v);
-						return true;
-					} else if (type.QualifiedName.Namespace == KnownTypeCollection.MSArraysNamespace &&
-						   IsPredefinedType (xe.ElementSchemaType.QualifiedName)) {
-						// then this CodeTypeDeclaration is to be removed, and CodeTypeReference to this type should be an array instead.
-						var cti = imported_types.First (i => i.XsdType == type);
-						cti.ClrType = new CodeTypeReference (GetCodeTypeReference (xe.ElementSchemaType.QualifiedName), 1);
-					
-						return false;
+						return ImportCollectionType (td, schemas, type, k, v);
 					}
 					}
-					else
-						Import (schemas, xe.ElementSchemaType);
-					td.BaseTypes.Add (new CodeTypeReference ("System.Collections.Generic.List", GetCodeTypeReference (xe.ElementSchemaType.QualifiedName)));
-					AddTypeAttributes (td, type, xe);
-					return true;
+					return ImportCollectionType (td, schemas, type, xe);
 				}
 				}
 			}
 			}
 			if (isDictionary)
 			if (isDictionary)
@@ -783,6 +840,92 @@ namespace System.Runtime.Serialization
 			return true;
 			return true;
 		}
 		}
 
 
+		bool ImportCollectionType (CodeTypeDeclaration td, XmlSchemaSet schemas,
+		                           XmlSchemaComplexType type,
+		                           XmlSchemaElement key, XmlSchemaElement value)
+		{
+			Import (schemas, key.ElementSchemaType);
+			Import (schemas, value.ElementSchemaType);
+			var keyType = GetCodeTypeReference (key.ElementSchemaType.QualifiedName);
+			var valueType = GetCodeTypeReference (value.ElementSchemaType.QualifiedName);
+
+			var collectionType = GetDictionaryCollectionType ();
+			var baseTypeName = collectionType != null ?
+				collectionType.FullName : "System.Collections.Generic.Dictionary";
+
+			if (type.QualifiedName.Name.StartsWith ("ArrayOf")) {
+				// Standard collection, use the collection type instead of
+				// creating a proxy class.
+				var cti = imported_types.First (i => i.XsdType == type);
+				cti.ClrType = new CodeTypeReference (baseTypeName, keyType, valueType);
+				return false;
+			}
+
+			td.BaseTypes.Add (new CodeTypeReference (baseTypeName, keyType, valueType));
+			AddTypeAttributes (td, type, key);
+			AddTypeAttributes (td, type, value);
+			return true;
+		}
+
+		bool ImportCollectionType (CodeTypeDeclaration td, XmlSchemaSet schemas,
+		                           XmlSchemaComplexType type, XmlSchemaElement xe)
+		{
+			Import (schemas, xe.ElementSchemaType);
+			var element = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName);
+
+			var collectionType = GetListCollectionType ();
+
+			if (type.QualifiedName.Name.StartsWith ("ArrayOf")) {
+				// Standard collection, use the collection type instead of
+				// creating a proxy class.
+				var cti = imported_types.First (i => i.XsdType == type);
+				if (collectionType != null)
+					cti.ClrType = new CodeTypeReference (collectionType.FullName, element);
+				else
+					cti.ClrType = new CodeTypeReference (element, 1);
+				return false;
+			}
+
+			var baseTypeName = collectionType != null ?
+				collectionType.FullName : "System.Collections.Generic.List";
+
+			td.BaseTypes.Add (new CodeTypeReference (baseTypeName, element));
+			AddTypeAttributes (td, type, xe);
+			return true;
+		}
+
+		bool ImplementsInterface (Type type, Type iface)
+		{
+			foreach (var i in type.GetInterfaces ()) {
+				if (i.Equals (iface))
+					return true;
+				if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (iface))
+					return true;
+			}
+
+			return false;
+		}
+
+		Type GetListCollectionType ()
+		{
+			if (import_options == null)
+				return null;
+			var listTypes = import_options.ReferencedCollectionTypes.Where (
+				t => t.IsGenericTypeDefinition && t.GetGenericArguments ().Length == 1 &&
+				ImplementsInterface (t, typeof (IEnumerable<>)));
+			return listTypes.FirstOrDefault ();
+		}
+
+		Type GetDictionaryCollectionType ()
+		{
+			if (import_options == null)
+				return null;
+			var dictTypes = import_options.ReferencedCollectionTypes.Where (
+				t => t.IsGenericTypeDefinition && t.GetGenericArguments ().Length == 2 &&
+				ImplementsInterface (t, typeof (IDictionary<,>)));
+			return dictTypes.FirstOrDefault ();
+		}
+
 		static readonly CodeExpression this_expr = new CodeThisReferenceExpression ();
 		static readonly CodeExpression this_expr = new CodeThisReferenceExpression ();
 		static readonly CodeExpression arg_value_expr = new CodePropertySetValueReferenceExpression ();
 		static readonly CodeExpression arg_value_expr = new CodePropertySetValueReferenceExpression ();
 
 
@@ -868,7 +1011,8 @@ namespace System.Runtime.Serialization
 
 
 		TypeImportInfo GetTypeInfo (XmlQualifiedName typeName, bool throwError)
 		TypeImportInfo GetTypeInfo (XmlQualifiedName typeName, bool throwError)
 		{
 		{
-			var info = imported_types.FirstOrDefault (i => i.XsdTypeName.Equals (typeName));
+			var info = imported_types.FirstOrDefault (
+				i => i.XsdTypeName.Equals (typeName) || i.XsdType.QualifiedName.Equals (typeName));
 			if (info == null) {
 			if (info == null) {
 				if (throwError)
 				if (throwError)
 					throw new InvalidOperationException (String.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName));
 					throw new InvalidOperationException (String.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName));

+ 3 - 0
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization_test.dll.sources

@@ -12,6 +12,9 @@ System.Runtime.Serialization/XmlObjectSerializerTest.cs
 System.Runtime.Serialization/XsdDataContractExporterTest.cs
 System.Runtime.Serialization/XsdDataContractExporterTest.cs
 System.Runtime.Serialization/XsdDataContractImporterTest.cs
 System.Runtime.Serialization/XsdDataContractImporterTest.cs
 System.Runtime.Serialization/CollectionSerialization.cs
 System.Runtime.Serialization/CollectionSerialization.cs
+System.Runtime.Serialization/WsdlHelper.cs
+System.Runtime.Serialization/XsdDataContractImporterTest2.cs
+System.Runtime.Serialization/XsdDataContractExporterTest2.cs
 System.Xml/UniqueIdTest.cs
 System.Xml/UniqueIdTest.cs
 System.Xml/XmlBinaryDictionaryReaderTest.cs
 System.Xml/XmlBinaryDictionaryReaderTest.cs
 System.Xml/XmlBinaryDictionaryWriterTest.cs
 System.Xml/XmlBinaryDictionaryWriterTest.cs

+ 236 - 0
mcs/class/System.Runtime.Serialization/Test/Resources/WSDL/collections.wsdl

@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wsdl:definitions name="MyService" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
+  <wsdl:types>
+    <xs:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+      <xs:import namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
+      <xs:import namespace="http://schemas.datacontract.org/2004/07/TestWCF.Model" />
+      <xs:element name="GetSimpleList">
+        <xs:complexType>
+          <xs:sequence />
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetSimpleListResponse">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element minOccurs="0" name="GetSimpleListResult" nillable="true" type="q1:ArrayOfint" xmlns:q1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetListOfStringArray">
+        <xs:complexType>
+          <xs:sequence />
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetListOfStringArrayResponse">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element minOccurs="0" name="GetListOfStringArrayResult" nillable="true" type="q2:ArrayOfArrayOfstring" xmlns:q2="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetListOfFoo">
+        <xs:complexType>
+          <xs:sequence />
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetListOfFooResponse">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element minOccurs="0" name="GetListOfFooResult" nillable="true" type="q3:ArrayOfFoo" xmlns:q3="http://schemas.datacontract.org/2004/07/TestWCF.Model" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetSimpleDictionary">
+        <xs:complexType>
+          <xs:sequence />
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetSimpleDictionaryResponse">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element minOccurs="0" name="GetSimpleDictionaryResult" nillable="true" type="q4:ArrayOfKeyValueOfintstring" xmlns:q4="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:schema>
+    <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/">
+      <xs:element name="anyType" nillable="true" type="xs:anyType" />
+      <xs:element name="anyURI" nillable="true" type="xs:anyURI" />
+      <xs:element name="base64Binary" nillable="true" type="xs:base64Binary" />
+      <xs:element name="boolean" nillable="true" type="xs:boolean" />
+      <xs:element name="byte" nillable="true" type="xs:byte" />
+      <xs:element name="dateTime" nillable="true" type="xs:dateTime" />
+      <xs:element name="decimal" nillable="true" type="xs:decimal" />
+      <xs:element name="double" nillable="true" type="xs:double" />
+      <xs:element name="float" nillable="true" type="xs:float" />
+      <xs:element name="int" nillable="true" type="xs:int" />
+      <xs:element name="long" nillable="true" type="xs:long" />
+      <xs:element name="QName" nillable="true" type="xs:QName" />
+      <xs:element name="short" nillable="true" type="xs:short" />
+      <xs:element name="string" nillable="true" type="xs:string" />
+      <xs:element name="unsignedByte" nillable="true" type="xs:unsignedByte" />
+      <xs:element name="unsignedInt" nillable="true" type="xs:unsignedInt" />
+      <xs:element name="unsignedLong" nillable="true" type="xs:unsignedLong" />
+      <xs:element name="unsignedShort" nillable="true" type="xs:unsignedShort" />
+      <xs:element name="char" nillable="true" type="tns:char" />
+      <xs:simpleType name="char">
+        <xs:restriction base="xs:int" />
+      </xs:simpleType>
+      <xs:element name="duration" nillable="true" type="tns:duration" />
+      <xs:simpleType name="duration">
+        <xs:restriction base="xs:duration">
+          <xs:pattern value="\-?P(\d*D)?(T(\d*H)?(\d*M)?(\d*(\.\d*)?S)?)?" />
+          <xs:minInclusive value="-P10675199DT2H48M5.4775808S" />
+          <xs:maxInclusive value="P10675199DT2H48M5.4775807S" />
+        </xs:restriction>
+      </xs:simpleType>
+      <xs:element name="guid" nillable="true" type="tns:guid" />
+      <xs:simpleType name="guid">
+        <xs:restriction base="xs:string">
+          <xs:pattern value="[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}" />
+        </xs:restriction>
+      </xs:simpleType>
+      <xs:attribute name="FactoryType" type="xs:QName" />
+      <xs:attribute name="Id" type="xs:ID" />
+      <xs:attribute name="Ref" type="xs:IDREF" />
+    </xs:schema>
+    <xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
+      <xs:complexType name="ArrayOfint">
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="int" type="xs:int" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="ArrayOfint" nillable="true" type="tns:ArrayOfint" />
+      <xs:complexType name="ArrayOfArrayOfstring">
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="ArrayOfstring" nillable="true" type="tns:ArrayOfstring" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="ArrayOfArrayOfstring" nillable="true" type="tns:ArrayOfArrayOfstring" />
+      <xs:complexType name="ArrayOfstring">
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="xs:string" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="ArrayOfstring" nillable="true" type="tns:ArrayOfstring" />
+      <xs:complexType name="ArrayOfKeyValueOfintstring">
+        <xs:annotation>
+          <xs:appinfo>
+            <IsDictionary xmlns="http://schemas.microsoft.com/2003/10/Serialization/">true</IsDictionary>
+          </xs:appinfo>
+        </xs:annotation>
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="KeyValueOfintstring">
+            <xs:complexType>
+              <xs:sequence>
+                <xs:element name="Key" type="xs:int" />
+                <xs:element name="Value" nillable="true" type="xs:string" />
+              </xs:sequence>
+            </xs:complexType>
+          </xs:element>
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="ArrayOfKeyValueOfintstring" nillable="true" type="tns:ArrayOfKeyValueOfintstring" />
+    </xs:schema>
+    <xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/TestWCF.Model" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/TestWCF.Model">
+      <xs:complexType name="ArrayOfFoo">
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="Foo" nillable="true" type="tns:Foo" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="ArrayOfFoo" nillable="true" type="tns:ArrayOfFoo" />
+      <xs:complexType name="Foo">
+        <xs:sequence>
+          <xs:element minOccurs="0" name="Text" nillable="true" type="xs:string" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="Foo" nillable="true" type="tns:Foo" />
+    </xs:schema>
+  </wsdl:types>
+  <wsdl:message name="IMyService_GetSimpleList_InputMessage">
+    <wsdl:part name="parameters" element="tns:GetSimpleList" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetSimpleList_OutputMessage">
+    <wsdl:part name="parameters" element="tns:GetSimpleListResponse" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetListOfStringArray_InputMessage">
+    <wsdl:part name="parameters" element="tns:GetListOfStringArray" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetListOfStringArray_OutputMessage">
+    <wsdl:part name="parameters" element="tns:GetListOfStringArrayResponse" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetListOfFoo_InputMessage">
+    <wsdl:part name="parameters" element="tns:GetListOfFoo" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetListOfFoo_OutputMessage">
+    <wsdl:part name="parameters" element="tns:GetListOfFooResponse" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetSimpleDictionary_InputMessage">
+    <wsdl:part name="parameters" element="tns:GetSimpleDictionary" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetSimpleDictionary_OutputMessage">
+    <wsdl:part name="parameters" element="tns:GetSimpleDictionaryResponse" />
+  </wsdl:message>
+  <wsdl:portType name="IMyService">
+    <wsdl:operation name="GetSimpleList">
+      <wsdl:input wsaw:Action="http://tempuri.org/IMyService/GetSimpleList" message="tns:IMyService_GetSimpleList_InputMessage" />
+      <wsdl:output wsaw:Action="http://tempuri.org/IMyService/GetSimpleListResponse" message="tns:IMyService_GetSimpleList_OutputMessage" />
+    </wsdl:operation>
+    <wsdl:operation name="GetListOfStringArray">
+      <wsdl:input wsaw:Action="http://tempuri.org/IMyService/GetListOfStringArray" message="tns:IMyService_GetListOfStringArray_InputMessage" />
+      <wsdl:output wsaw:Action="http://tempuri.org/IMyService/GetListOfStringArrayResponse" message="tns:IMyService_GetListOfStringArray_OutputMessage" />
+    </wsdl:operation>
+    <wsdl:operation name="GetListOfFoo">
+      <wsdl:input wsaw:Action="http://tempuri.org/IMyService/GetListOfFoo" message="tns:IMyService_GetListOfFoo_InputMessage" />
+      <wsdl:output wsaw:Action="http://tempuri.org/IMyService/GetListOfFooResponse" message="tns:IMyService_GetListOfFoo_OutputMessage" />
+    </wsdl:operation>
+    <wsdl:operation name="GetSimpleDictionary">
+      <wsdl:input wsaw:Action="http://tempuri.org/IMyService/GetSimpleDictionary" message="tns:IMyService_GetSimpleDictionary_InputMessage" />
+      <wsdl:output wsaw:Action="http://tempuri.org/IMyService/GetSimpleDictionaryResponse" message="tns:IMyService_GetSimpleDictionary_OutputMessage" />
+    </wsdl:operation>
+  </wsdl:portType>
+  <wsdl:binding name="defaultEndpoint" type="tns:IMyService">
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
+    <wsdl:operation name="GetSimpleList">
+      <soap:operation soapAction="http://tempuri.org/IMyService/GetSimpleList" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+    <wsdl:operation name="GetListOfStringArray">
+      <soap:operation soapAction="http://tempuri.org/IMyService/GetListOfStringArray" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+    <wsdl:operation name="GetListOfFoo">
+      <soap:operation soapAction="http://tempuri.org/IMyService/GetListOfFoo" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+    <wsdl:operation name="GetSimpleDictionary">
+      <soap:operation soapAction="http://tempuri.org/IMyService/GetSimpleDictionary" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:service name="MyService">
+    <wsdl:port name="defaultEndpoint" binding="tns:defaultEndpoint">
+      <soap:address location="http://provcon-faust/TestWCF/MyService.svc" />
+    </wsdl:port>
+  </wsdl:service>
+</wsdl:definitions>

+ 142 - 0
mcs/class/System.Runtime.Serialization/Test/Resources/WSDL/custom-collections.wsdl

@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wsdl:definitions name="MyService" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
+  <wsdl:types>
+    <xs:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+      <xs:import namespace="http://schemas.datacontract.org/2004/07/TestWCF.Model" />
+      <xs:element name="GetCustomCollection">
+        <xs:complexType>
+          <xs:sequence />
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetCustomCollectionResponse">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element minOccurs="0" name="GetCustomCollectionResult" nillable="true" type="q1:MyCollection" xmlns:q1="http://schemas.datacontract.org/2004/07/TestWCF.Model" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetCustomCollection2">
+        <xs:complexType>
+          <xs:sequence />
+        </xs:complexType>
+      </xs:element>
+      <xs:element name="GetCustomCollection2Response">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element minOccurs="0" name="GetCustomCollection2Result" nillable="true" type="q2:MyCollectionOfdouble" xmlns:q2="http://schemas.datacontract.org/2004/07/TestWCF.Model" />
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element>
+    </xs:schema>
+    <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/">
+      <xs:element name="anyType" nillable="true" type="xs:anyType" />
+      <xs:element name="anyURI" nillable="true" type="xs:anyURI" />
+      <xs:element name="base64Binary" nillable="true" type="xs:base64Binary" />
+      <xs:element name="boolean" nillable="true" type="xs:boolean" />
+      <xs:element name="byte" nillable="true" type="xs:byte" />
+      <xs:element name="dateTime" nillable="true" type="xs:dateTime" />
+      <xs:element name="decimal" nillable="true" type="xs:decimal" />
+      <xs:element name="double" nillable="true" type="xs:double" />
+      <xs:element name="float" nillable="true" type="xs:float" />
+      <xs:element name="int" nillable="true" type="xs:int" />
+      <xs:element name="long" nillable="true" type="xs:long" />
+      <xs:element name="QName" nillable="true" type="xs:QName" />
+      <xs:element name="short" nillable="true" type="xs:short" />
+      <xs:element name="string" nillable="true" type="xs:string" />
+      <xs:element name="unsignedByte" nillable="true" type="xs:unsignedByte" />
+      <xs:element name="unsignedInt" nillable="true" type="xs:unsignedInt" />
+      <xs:element name="unsignedLong" nillable="true" type="xs:unsignedLong" />
+      <xs:element name="unsignedShort" nillable="true" type="xs:unsignedShort" />
+      <xs:element name="char" nillable="true" type="tns:char" />
+      <xs:simpleType name="char">
+        <xs:restriction base="xs:int" />
+      </xs:simpleType>
+      <xs:element name="duration" nillable="true" type="tns:duration" />
+      <xs:simpleType name="duration">
+        <xs:restriction base="xs:duration">
+          <xs:pattern value="\-?P(\d*D)?(T(\d*H)?(\d*M)?(\d*(\.\d*)?S)?)?" />
+          <xs:minInclusive value="-P10675199DT2H48M5.4775808S" />
+          <xs:maxInclusive value="P10675199DT2H48M5.4775807S" />
+        </xs:restriction>
+      </xs:simpleType>
+      <xs:element name="guid" nillable="true" type="tns:guid" />
+      <xs:simpleType name="guid">
+        <xs:restriction base="xs:string">
+          <xs:pattern value="[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}" />
+        </xs:restriction>
+      </xs:simpleType>
+      <xs:attribute name="FactoryType" type="xs:QName" />
+      <xs:attribute name="Id" type="xs:ID" />
+      <xs:attribute name="Ref" type="xs:IDREF" />
+    </xs:schema>
+    <xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/TestWCF.Model" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/TestWCF.Model">
+      <xs:complexType name="MyCollection">
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="xs:string" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="MyCollection" nillable="true" type="tns:MyCollection" />
+      <xs:complexType name="MyCollectionOfdouble">
+        <xs:annotation>
+          <xs:appinfo>
+            <GenericType Name="MyCollectionOf{0}" Namespace="http://schemas.datacontract.org/2004/07/TestWCF.Model" xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
+              <GenericParameter Name="double" Namespace="http://www.w3.org/2001/XMLSchema" />
+            </GenericType>
+          </xs:appinfo>
+        </xs:annotation>
+        <xs:sequence>
+          <xs:element minOccurs="0" maxOccurs="unbounded" name="double" type="xs:double" />
+        </xs:sequence>
+      </xs:complexType>
+      <xs:element name="MyCollectionOfdouble" nillable="true" type="tns:MyCollectionOfdouble" />
+    </xs:schema>
+  </wsdl:types>
+  <wsdl:message name="IMyService_GetCustomCollection_InputMessage">
+    <wsdl:part name="parameters" element="tns:GetCustomCollection" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetCustomCollection_OutputMessage">
+    <wsdl:part name="parameters" element="tns:GetCustomCollectionResponse" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetCustomCollection2_InputMessage">
+    <wsdl:part name="parameters" element="tns:GetCustomCollection2" />
+  </wsdl:message>
+  <wsdl:message name="IMyService_GetCustomCollection2_OutputMessage">
+    <wsdl:part name="parameters" element="tns:GetCustomCollection2Response" />
+  </wsdl:message>
+  <wsdl:portType name="IMyService">
+    <wsdl:operation name="GetCustomCollection">
+      <wsdl:input wsaw:Action="http://tempuri.org/IMyService/GetCustomCollection" message="tns:IMyService_GetCustomCollection_InputMessage" />
+      <wsdl:output wsaw:Action="http://tempuri.org/IMyService/GetCustomCollectionResponse" message="tns:IMyService_GetCustomCollection_OutputMessage" />
+    </wsdl:operation>
+    <wsdl:operation name="GetCustomCollection2">
+      <wsdl:input wsaw:Action="http://tempuri.org/IMyService/GetCustomCollection2" message="tns:IMyService_GetCustomCollection2_InputMessage" />
+      <wsdl:output wsaw:Action="http://tempuri.org/IMyService/GetCustomCollection2Response" message="tns:IMyService_GetCustomCollection2_OutputMessage" />
+    </wsdl:operation>
+  </wsdl:portType>
+  <wsdl:binding name="defaultEndpoint" type="tns:IMyService">
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
+    <wsdl:operation name="GetCustomCollection">
+      <soap:operation soapAction="http://tempuri.org/IMyService/GetCustomCollection" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+    <wsdl:operation name="GetCustomCollection2">
+      <soap:operation soapAction="http://tempuri.org/IMyService/GetCustomCollection2" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:service name="MyService">
+    <wsdl:port name="defaultEndpoint" binding="tns:defaultEndpoint">
+      <soap:address location="http://provcon-faust/TestWCF/MyService.svc" />
+    </wsdl:port>
+  </wsdl:service>
+</wsdl:definitions>

+ 178 - 0
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/WsdlHelper.cs

@@ -0,0 +1,178 @@
+//
+// WsdlHelper.cs
+//
+// Author:
+//       Martin Baulig <[email protected]>
+//
+// Copyright (c) 2012 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.ServiceModel.Description;
+using System.Web.Services.Discovery;
+using System.Runtime.Serialization;
+using WebServices = System.Web.Services;
+using System.CodeDom;
+
+namespace MonoTests.System.Runtime.Serialization
+{
+	public static class WsdlHelper
+	{
+		/*
+		 * This reads a normal .wsdl file from an embedded resource.
+		 * 
+		 * You can simply fetch them from your server using
+		 * 'curl http://yourserver/YourService.svc?singleWsdl > YourService.wsdl',
+		 * add the .wsdl file to Test/Resources/WSDL and add it to `TEST_RESOURCE_FILES'
+		 * in the Makefile.
+		 */
+
+		public static MetadataSet GetMetadataSet (string name)
+		{
+			var asm = Assembly.GetExecutingAssembly ();
+			using (var stream = asm.GetManifestResourceStream (name)) {
+				if (stream == null)
+					throw new InvalidOperationException (string.Format (
+						"Cannot find resource file '{0}'.", name));
+				return GetMetadataSet (stream);
+			}
+		}
+		
+		public static MetadataSet GetMetadataSet (Stream stream)
+		{
+			var dr = new ContractReference ();
+			var doc = (WebServices.Description.ServiceDescription) dr.ReadDocument (stream);
+			
+			var metadata = new MetadataSet ();
+			metadata.MetadataSections.Add (
+				new MetadataSection (MetadataSection.ServiceDescriptionDialect, "", doc));
+			return metadata;
+		}
+
+		public static CodeCompileUnit Import (MetadataSet metadata, ImportOptions options)
+		{
+			var importer = new WsdlImporter (metadata);
+			var xsdImporter = new XsdDataContractImporter ();
+			xsdImporter.Options = options;
+			importer.State.Add (typeof(XsdDataContractImporter), xsdImporter);
+			
+			var contracts = importer.ImportAllContracts ();
+			
+			CodeCompileUnit ccu = new CodeCompileUnit ();
+			var generator = new ServiceContractGenerator (ccu);
+
+			if (contracts.Count != 1)
+				throw new InvalidOperationException (string.Format (
+					"Metadata import failed: found {0} contracts.", contracts.Count));
+			
+			var contract = contracts.First ();
+			generator.GenerateServiceContractType (contract);
+			
+			return ccu;
+		}
+
+		public static CodeNamespace Find (this CodeNamespaceCollection collection, string name)
+		{
+			foreach (CodeNamespace ns in collection) {
+				if (ns.Name == name)
+					return ns;
+			}
+			
+			return null;
+		}
+		
+		public static CodeNamespace FindNamespace (this CodeCompileUnit unit, string name)
+		{
+			foreach (CodeNamespace ns in unit.Namespaces) {
+				if (ns.Name == name)
+					return ns;
+			}
+			
+			return null;
+		}
+		
+		public static CodeTypeDeclaration FindType (this CodeNamespace ns, string name)
+		{
+			foreach (CodeTypeDeclaration type in ns.Types) {
+				if (type.Name == name)
+					return type;
+			}
+			
+			return null;
+		}
+		
+		public static CodeTypeDeclaration FindType (this CodeCompileUnit unit, string name)
+		{
+			foreach (CodeNamespace ns in unit.Namespaces) {
+				foreach (CodeTypeDeclaration type in ns.Types) {
+					if (type.Name == name)
+						return type;
+				}
+			}
+			
+			return null;
+		}
+		
+		public static CodeMemberMethod FindMethod (this CodeTypeDeclaration type, string name)
+		{
+			foreach (var member in type.Members) {
+				var method = member as CodeMemberMethod;
+				if (method == null)
+					continue;
+				if (method.Name == name)
+					return method;
+			}
+			
+			return null;
+		}
+		
+		public static CodeMemberMethod FindMethod (this CodeCompileUnit unit, string typeName,
+		                                           string methodName)
+		{
+			var type = unit.FindType (typeName);
+			if (type == null)
+				return null;
+			return type.FindMethod (methodName);
+		}
+
+		public static CodeAttributeDeclaration FindAttribute (this CodeTypeDeclaration type, string name)
+		{
+			foreach (CodeAttributeDeclaration attr in type.CustomAttributes) {
+				if (attr.Name == name)
+					return attr;
+			}
+
+			return null;
+		}
+
+		public static CodeAttributeArgument FindArgument (this CodeAttributeDeclaration attr, string name)
+		{
+			foreach (CodeAttributeArgument arg in attr.Arguments) {
+				if (arg.Name == name)
+					return arg;
+			}
+
+			return null;
+		}
+	}
+}
+

+ 171 - 0
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractExporterTest2.cs

@@ -0,0 +1,171 @@
+//
+// XsdDataContractExporterTest2.cs
+//
+// Author:
+//       Martin Baulig <[email protected]>
+//
+// Copyright (c) 2012 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.CodeDom;
+using System.CodeDom.Compiler;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.ServiceModel;
+using System.ServiceModel.Description;
+using System.Web.Services.Discovery;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+using Microsoft.CSharp;
+using NUnit.Framework;
+using NUnit.Framework.Constraints;
+using NUnit.Framework.SyntaxHelpers;
+
+using QName = System.Xml.XmlQualifiedName;
+
+namespace MonoTests.System.Runtime.Serialization
+{
+	[TestFixture]
+	public class XsdDataContractExporterTest2
+	{
+		internal const string MSArraysNamespace =
+			"http://schemas.microsoft.com/2003/10/Serialization/Arrays";
+
+		[Test]
+		public void ExportList ()
+		{
+			var exporter = new XsdDataContractExporter ();
+			Assert.That (exporter.CanExport (typeof(MyService)), Is.True, "#1");
+			exporter.Export (typeof(MyService));
+
+			var typeName = exporter.GetSchemaTypeName (typeof(MyService));
+			var type = exporter.Schemas.GlobalTypes [typeName];
+
+			Assert.That (type, Is.Not.Null, "#2");
+			Assert.That (type, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#3");
+
+			var complex = (XmlSchemaComplexType)type;
+			Assert.That (complex.Annotation, Is.Null, "#4");
+
+			var sequence = complex.Particle as XmlSchemaSequence;
+			Assert.That (sequence, Is.Not.Null, "#5");
+			Assert.That (sequence.Items.Count, Is.EqualTo (3), "#5a");
+			Assert.That (sequence.Annotation, Is.Null, "#5b");
+			Assert.That (sequence.MinOccursString, Is.Null, "#5c");
+			Assert.That (sequence.MaxOccursString, Is.Null, "#5d");
+
+			var list = GetElement (sequence, "list");
+			Assert.That (list, Is.Not.Null, "#6");
+			Assert.That (list.Annotation, Is.Null, "#6a");
+			Assert.That (list.Name, Is.EqualTo ("list"), "#6b");
+			Assert.That (list.ElementSchemaType, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#6c");
+
+			var listElement = (XmlSchemaComplexType)list.ElementSchemaType;
+			Assert.That (listElement.QualifiedName.Namespace, Is.EqualTo (MSArraysNamespace), "#6d");
+			Assert.That (listElement.QualifiedName.Name, Is.EqualTo ("ArrayOfint"), "#6e");
+
+			Assert.That (listElement.Particle, Is.InstanceOfType (typeof(XmlSchemaSequence)), "#7");
+			var listSeq = (XmlSchemaSequence)listElement.Particle;
+			Assert.That (listSeq.Items.Count, Is.EqualTo (1), "#7b");
+			Assert.That (listSeq.Items[0], Is.InstanceOfType (typeof(XmlSchemaElement)), "#7c");
+			Assert.That (listSeq.Annotation, Is.Null, "#7d");
+
+			var listSeqElement = (XmlSchemaElement)listSeq.Items[0];
+			Assert.That (listSeqElement.MaxOccursString, Is.EqualTo ("unbounded"), "#7e");
+			Assert.That (listSeqElement.MinOccursString, Is.EqualTo ("0"), "#7f");
+
+			var dict = GetElement (sequence, "dictionary");
+			Assert.That (dict, Is.Not.Null, "#8");
+			Assert.That (dict.Annotation, Is.Null, "#8a");
+			Assert.That (dict.Name, Is.EqualTo ("dictionary"), "#8b");
+			Assert.That (dict.ElementSchemaType, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#8c");
+			
+			var dictElement = (XmlSchemaComplexType)dict.ElementSchemaType;
+			Assert.That (dictElement.QualifiedName.Namespace, Is.EqualTo (MSArraysNamespace), "#8d");
+			Assert.That (dictElement.QualifiedName.Name, Is.EqualTo ("ArrayOfKeyValueOfstringdouble"), "#8e");
+
+			Assert.That (dictElement.Particle, Is.InstanceOfType (typeof(XmlSchemaSequence)), "#9");
+			var dictSeq = (XmlSchemaSequence)dictElement.Particle;
+			Assert.That (dictSeq.Items.Count, Is.EqualTo (1), "#9b");
+			Assert.That (dictSeq.Items[0], Is.InstanceOfType (typeof(XmlSchemaElement)), "#9c");
+			Assert.That (dictSeq.Annotation, Is.Null, "#9d");
+			
+			var dictSeqElement = (XmlSchemaElement)dictSeq.Items[0];
+			Assert.That (listSeqElement.MaxOccursString, Is.EqualTo ("unbounded"), "#9e");
+			Assert.That (listSeqElement.MinOccursString, Is.EqualTo ("0"), "#9f");
+
+
+			var custom = GetElement (sequence, "customCollection");
+			Assert.That (custom, Is.Not.Null, "#10");
+			Assert.That (custom.Annotation, Is.Null, "#10a");
+			Assert.That (custom.Name, Is.EqualTo ("customCollection"), "#10b");
+			Assert.That (custom.ElementSchemaType, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#10c");
+			
+			var customElement = (XmlSchemaComplexType)custom.ElementSchemaType;
+			var customEQN = customElement.QualifiedName;
+			Assert.That (customEQN.Namespace, Is.EqualTo (typeName.Namespace), "#10d");
+			Assert.That (customEQN.Name.StartsWith ("XsdDataContractExporterTest2.MyCollectionOfstring", StringComparison.InvariantCultureIgnoreCase),
+			             Is.True, "#10e");
+
+			Assert.That (customElement.Particle, Is.InstanceOfType (typeof(XmlSchemaSequence)), "#11");
+			var customSeq = (XmlSchemaSequence)customElement.Particle;
+			Assert.That (customSeq.Items.Count, Is.EqualTo (1), "#11b");
+			Assert.That (customSeq.Items[0], Is.InstanceOfType (typeof(XmlSchemaElement)), "#11c");
+			Assert.That (customSeq.Annotation, Is.Null, "#11d");
+			
+			var customSeqElement = (XmlSchemaElement)customSeq.Items[0];
+			Assert.That (customSeqElement.MaxOccursString, Is.EqualTo ("unbounded"), "#11e");
+			Assert.That (customSeqElement.MinOccursString, Is.EqualTo ("0"), "#11f");
+		}
+
+		static XmlSchemaElement GetElement (XmlSchemaSequence sequence, string name)
+		{
+			foreach (XmlSchemaElement item in sequence.Items) {
+				if (item.Name.Equals (name))
+					return item;
+			}
+
+			return null;
+		}
+
+		[ServiceContract]
+		public class MyService
+		{
+			[DataMember]
+			public List<int> list;
+
+			[DataMember]
+			public Dictionary<string,double> dictionary;
+
+			[DataMember]
+			public MyCollection<string> customCollection;
+		}
+
+		[CollectionDataContract]
+		public class MyCollection<T> : List<T>
+		{
+		}
+	}
+}

+ 359 - 0
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractImporterTest2.cs

@@ -0,0 +1,359 @@
+//
+// XsdDataContractImporterTest2.cs
+//
+// Author:
+//       Martin Baulig <[email protected]>
+//
+// Copyright (c) 2012 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.CodeDom;
+using System.CodeDom.Compiler;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.ServiceModel.Description;
+using System.Web.Services.Discovery;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+using Microsoft.CSharp;
+using NUnit.Framework;
+using NUnit.Framework.Constraints;
+using NUnit.Framework.SyntaxHelpers;
+
+using QName = System.Xml.XmlQualifiedName;
+
+namespace MonoTests.System.Runtime.Serialization
+{
+	[TestFixture]
+	public class XsdDataContractImporterTest2
+	{
+		MetadataSet collectionsMetadata;
+		MetadataSet customCollectionsMetadata;
+
+		[SetUp]
+		public void Setup ()
+		{
+			collectionsMetadata = WsdlHelper.GetMetadataSet ("collections.wsdl");
+			customCollectionsMetadata = WsdlHelper.GetMetadataSet ("custom-collections.wsdl");
+		}
+		
+		[Test]
+		public void TestSimpleList ()
+		{
+			var options = new ImportOptions ();
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetSimpleList");
+			Assert.That (method, Is.Not.Null, "#1");
+			Assert.That (method.ReturnType, Is.Not.Null, "#2");
+			
+			Assert.That (method.ReturnType.ArrayRank, Is.EqualTo (1), "#3");
+			Assert.That (method.ReturnType.BaseType, Is.EqualTo ("System.Int32"), "#4");
+		}
+		
+		[Test]
+		public void TestSimpleList2 ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof(LinkedList<>));
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetSimpleList");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("System.Collections.Generic.LinkedList`1"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (1), "#5");
+			Assert.That (ret.TypeArguments [0].BaseType, Is.EqualTo ("System.Int32"), "#6");
+		}
+		
+		[Test]
+		public void TestSimpleList3 ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof (Dictionary<,>));
+			options.ReferencedCollectionTypes.Add (typeof (ObservableCollection<>));
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetSimpleList");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("System.Collections.ObjectModel.ObservableCollection`1"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (1), "#5");
+			Assert.That (ret.TypeArguments [0].BaseType, Is.EqualTo ("System.Int32"), "#6");
+		}
+		
+		[Test]
+		public void TestListOfFoo ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof (List<>));
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetListOfFoo");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("System.Collections.Generic.List`1"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (1), "#5");
+			Assert.That (ret.TypeArguments [0].BaseType, Is.EqualTo ("TestWCF.Model.Foo"), "#6");
+		}
+		
+		[Test]
+		public void TestListOfStringArray ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof (List<>));
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetListOfStringArray");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("System.Collections.Generic.List`1"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (1), "#5");
+			
+			var baseType = ret.TypeArguments [0];
+			Assert.That (baseType.BaseType, Is.EqualTo ("System.Collections.Generic.List`1"), "#6");
+			Assert.That (baseType.TypeArguments.Count, Is.EqualTo (1), "#7");
+			Assert.That (baseType.TypeArguments [0].BaseType, Is.EqualTo ("System.String"), "#8");
+		}
+		
+		[Test]
+		public void TestSimpleDictionary ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof (List<>));
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetSimpleDictionary");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("System.Collections.Generic.Dictionary`2"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (2), "#5");
+			
+			var keyType = ret.TypeArguments [0];
+			Assert.That (keyType.BaseType, Is.EqualTo ("System.Int32"), "#6");
+			var valueType = ret.TypeArguments [1];
+			Assert.That (valueType.BaseType, Is.EqualTo ("System.String"), "#7");
+		}
+		
+		[Test]
+		public void TestSimpleDictionary2 ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof (SortedList<,>));
+			
+			var ccu = WsdlHelper.Import (collectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetSimpleDictionary");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("System.Collections.Generic.SortedList`2"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (2), "#5");
+			
+			var keyType = ret.TypeArguments [0];
+			Assert.That (keyType.BaseType, Is.EqualTo ("System.Int32"), "#6");
+			var valueType = ret.TypeArguments [1];
+			Assert.That (valueType.BaseType, Is.EqualTo ("System.String"), "#7");
+		}
+
+		[Test]
+		public void TestCustomCollection ()
+		{
+			var options = new ImportOptions ();
+			
+			var ccu = WsdlHelper.Import (customCollectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetCustomCollection");
+			Assert.That (method, Is.Not.Null, "#1");
+
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("TestWCF.Model.MyCollection"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (0), "#5");
+		}
+
+		[Test]
+		public void TestCustomCollection2 ()
+		{
+			var options = new ImportOptions ();
+
+			var ccu = WsdlHelper.Import (customCollectionsMetadata, options);
+			
+			var method = ccu.FindMethod ("MyServiceClient", "GetCustomCollection2");
+			Assert.That (method, Is.Not.Null, "#1");
+			
+			var ret = method.ReturnType;
+			Assert.That (ret, Is.Not.Null, "#2");
+			
+			Assert.That (ret.ArrayRank, Is.EqualTo (0), "#3");
+			Assert.That (ret.BaseType, Is.EqualTo ("TestWCF.Model.MyCollectionOfdouble"), "#4");
+			Assert.That (ret.TypeArguments.Count, Is.EqualTo (0), "#5");
+		}
+
+		[Test]
+		public void TestCustomCollection3 ()
+		{
+			var options = new ImportOptions ();
+
+			var ccu = WsdlHelper.Import (customCollectionsMetadata, options);
+			
+			var type = ccu.FindType ("MyCollection");
+			Assert.That (type, Is.Not.Null, "#1a");
+			Assert.That (type.BaseTypes.Count, Is.EqualTo (1), "#2a");
+			
+			var baseType = type.BaseTypes[0];
+			Assert.That (baseType.BaseType, Is.EqualTo ("System.Collections.Generic.List`1"), "#3a");
+			Assert.That (baseType.TypeArguments.Count, Is.EqualTo (1), "#4a");
+			Assert.That (baseType.TypeArguments[0].BaseType, Is.EqualTo ("System.String"), "#5a");
+
+			var attr = type.FindAttribute ("System.Runtime.Serialization.CollectionDataContractAttribute");
+			Assert.That (attr, Is.Not.Null, "#6a");
+
+			var nameArg = attr.FindArgument ("Name");
+			Assert.That (nameArg, Is.Not.Null, "#7a");
+			Assert.That (((CodePrimitiveExpression)nameArg.Value).Value, Is.EqualTo ("MyCollection"), "#8a");
+
+			var nsArg = attr.FindArgument ("Namespace");
+			Assert.That (nsArg, Is.Not.Null, "#9a");
+			Assert.That (((CodePrimitiveExpression)nsArg.Value).Value, Is.EqualTo ("http://schemas.datacontract.org/2004/07/TestWCF.Model"), "#10a");
+			
+			var itemArg = attr.FindArgument ("ItemName");
+			Assert.That (itemArg, Is.Not.Null);
+			Assert.That (((CodePrimitiveExpression)itemArg.Value).Value, Is.EqualTo ("string"), "#11a");
+
+			type = ccu.FindType ("MyCollectionOfdouble");
+			Assert.That (type, Is.Not.Null, "#1b");
+			Assert.That (type.BaseTypes.Count, Is.EqualTo (1), "#2b");
+
+			baseType = type.BaseTypes[0];
+			Assert.That (baseType.BaseType, Is.EqualTo ("System.Collections.Generic.List`1"), "#3b");
+			Assert.That (baseType.TypeArguments.Count, Is.EqualTo (1), "#4b");
+			Assert.That (baseType.TypeArguments[0].BaseType, Is.EqualTo ("System.Double"), "#5b");
+			
+			attr = type.FindAttribute ("System.Runtime.Serialization.CollectionDataContractAttribute");
+			Assert.That (attr, Is.Not.Null, "#6b");
+			
+			nameArg = attr.FindArgument ("Name");
+			Assert.That (nameArg, Is.Not.Null, "#7b");
+			Assert.That (((CodePrimitiveExpression)nameArg.Value).Value, Is.EqualTo ("MyCollectionOfdouble"), "#8b");
+			
+			nsArg = attr.FindArgument ("Namespace");
+			Assert.That (nsArg, Is.Not.Null, "#9b");
+			Assert.That (((CodePrimitiveExpression)nsArg.Value).Value, Is.EqualTo ("http://schemas.datacontract.org/2004/07/TestWCF.Model"), "#10b");
+			
+			itemArg = attr.FindArgument ("ItemName");
+			Assert.That (itemArg, Is.Not.Null);
+			Assert.That (((CodePrimitiveExpression)itemArg.Value).Value, Is.EqualTo ("double"), "#11b");
+		}
+
+		[Test]
+		public void TestCustomCollection4 ()
+		{
+			var options = new ImportOptions ();
+			options.ReferencedCollectionTypes.Add (typeof (LinkedList<>));
+
+			var ccu = WsdlHelper.Import (customCollectionsMetadata, options);
+			
+			var type = ccu.FindType ("MyCollection");
+			Assert.That (type, Is.Not.Null, "#1a");
+			Assert.That (type.BaseTypes.Count, Is.EqualTo (1), "#2a");
+			
+			var baseType = type.BaseTypes[0];
+			Assert.That (baseType.BaseType, Is.EqualTo ("System.Collections.Generic.LinkedList`1"), "#3a");
+			Assert.That (baseType.TypeArguments.Count, Is.EqualTo (1), "#4a");
+			Assert.That (baseType.TypeArguments[0].BaseType, Is.EqualTo ("System.String"), "#5a");
+			
+			var attr = type.FindAttribute ("System.Runtime.Serialization.CollectionDataContractAttribute");
+			Assert.That (attr, Is.Not.Null, "#6a");
+			
+			var nameArg = attr.FindArgument ("Name");
+			Assert.That (nameArg, Is.Not.Null, "#7a");
+			Assert.That (((CodePrimitiveExpression)nameArg.Value).Value, Is.EqualTo ("MyCollection"), "#8a");
+			
+			var nsArg = attr.FindArgument ("Namespace");
+			Assert.That (nsArg, Is.Not.Null, "#9a");
+			Assert.That (((CodePrimitiveExpression)nsArg.Value).Value, Is.EqualTo ("http://schemas.datacontract.org/2004/07/TestWCF.Model"), "#10a");
+			
+			var itemArg = attr.FindArgument ("ItemName");
+			Assert.That (itemArg, Is.Not.Null);
+			Assert.That (((CodePrimitiveExpression)itemArg.Value).Value, Is.EqualTo ("string"), "#11a");
+			
+			type = ccu.FindType ("MyCollectionOfdouble");
+			Assert.That (type, Is.Not.Null, "#1b");
+			Assert.That (type.BaseTypes.Count, Is.EqualTo (1), "#2b");
+			
+			baseType = type.BaseTypes[0];
+			Assert.That (baseType.BaseType, Is.EqualTo ("System.Collections.Generic.LinkedList`1"), "#3b");
+			Assert.That (baseType.TypeArguments.Count, Is.EqualTo (1), "#4b");
+			Assert.That (baseType.TypeArguments[0].BaseType, Is.EqualTo ("System.Double"), "#5b");
+			
+			attr = type.FindAttribute ("System.Runtime.Serialization.CollectionDataContractAttribute");
+			Assert.That (attr, Is.Not.Null, "#6b");
+			
+			nameArg = attr.FindArgument ("Name");
+			Assert.That (nameArg, Is.Not.Null, "#7b");
+			Assert.That (((CodePrimitiveExpression)nameArg.Value).Value, Is.EqualTo ("MyCollectionOfdouble"), "#8b");
+			
+			nsArg = attr.FindArgument ("Namespace");
+			Assert.That (nsArg, Is.Not.Null, "#9b");
+			Assert.That (((CodePrimitiveExpression)nsArg.Value).Value, Is.EqualTo ("http://schemas.datacontract.org/2004/07/TestWCF.Model"), "#10b");
+			
+			itemArg = attr.FindArgument ("ItemName");
+			Assert.That (itemArg, Is.Not.Null);
+			Assert.That (((CodePrimitiveExpression)itemArg.Value).Value, Is.EqualTo ("double"), "#11b");
+		}
+	}
+}

+ 18 - 2
mcs/class/System.ServiceModel/System.ServiceModel.Description/DataContractSerializerMessageContractImporter.cs

@@ -88,6 +88,8 @@ namespace System.ServiceModel.Description
 
 
 	abstract class MessageContractImporterInternal : IWsdlImportExtension
 	abstract class MessageContractImporterInternal : IWsdlImportExtension
 	{
 	{
+		protected abstract void Init (WsdlImporter importer);
+
 		public void ImportContract (WsdlImporter importer,
 		public void ImportContract (WsdlImporter importer,
 			WsdlContractConversionContext context)
 			WsdlContractConversionContext context)
 		{
 		{
@@ -98,6 +100,8 @@ namespace System.ServiceModel.Description
 			if (this.importer != null || this.context != null)
 			if (this.importer != null || this.context != null)
 				throw new SystemException ("INTERNAL ERROR: unexpected recursion of ImportContract method call");
 				throw new SystemException ("INTERNAL ERROR: unexpected recursion of ImportContract method call");
 
 
+			Init (importer);
+
 			schema_set_in_use = new XmlSchemaSet ();
 			schema_set_in_use = new XmlSchemaSet ();
 			schema_set_in_use.Add (importer.XmlSchemas);
 			schema_set_in_use.Add (importer.XmlSchemas);
 			foreach (WSDL wsdl in importer.WsdlDocuments)
 			foreach (WSDL wsdl in importer.WsdlDocuments)
@@ -237,8 +241,14 @@ namespace System.ServiceModel.Description
 
 
 	class DataContractMessageContractImporterInternal : MessageContractImporterInternal
 	class DataContractMessageContractImporterInternal : MessageContractImporterInternal
 	{
 	{
-		XsdDataContractImporter dc_importer = new XsdDataContractImporter ();
+		XsdDataContractImporter dc_importer;
 		
 		
+		protected override void Init (WsdlImporter importer)
+		{
+			if (dc_importer == null)
+				dc_importer = importer.GetState<XsdDataContractImporter> ();
+		}
+
 		protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart part)
 		protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart part)
 		{
 		{
 			XmlSchemaElement element = (XmlSchemaElement) schema_set_in_use.GlobalElements [qname];
 			XmlSchemaElement element = (XmlSchemaElement) schema_set_in_use.GlobalElements [qname];
@@ -325,7 +335,7 @@ namespace System.ServiceModel.Description
 
 
 	class XmlSerializerMessageContractImporterInternal : MessageContractImporterInternal
 	class XmlSerializerMessageContractImporterInternal : MessageContractImporterInternal
 	{
 	{
-		CodeCompileUnit ccu = new CodeCompileUnit ();
+		CodeCompileUnit ccu;
 		XmlSchemaSet schema_set_cache;
 		XmlSchemaSet schema_set_cache;
 		XmlSchemaImporter schema_importer;
 		XmlSchemaImporter schema_importer;
 		XmlCodeExporter code_exporter;
 		XmlCodeExporter code_exporter;
@@ -333,6 +343,12 @@ namespace System.ServiceModel.Description
 		public CodeCompileUnit CodeCompileUnit {
 		public CodeCompileUnit CodeCompileUnit {
 			get { return ccu; }
 			get { return ccu; }
 		}
 		}
+
+		protected override void Init (WsdlImporter importer)
+		{
+			if (ccu == null)
+				ccu = importer.GetState<CodeCompileUnit> ();
+		}
 		
 		
 		protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart msgPart)
 		protected override void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, Message msg, MessagePart msgPart)
 		{
 		{

+ 12 - 1
mcs/class/System.ServiceModel/System.ServiceModel.Description/MetadataImporter.cs

@@ -41,6 +41,7 @@ namespace System.ServiceModel.Description
 	{
 	{
 		KeyedByTypeCollection<IPolicyImportExtension> policy_extensions;
 		KeyedByTypeCollection<IPolicyImportExtension> policy_extensions;
 		Collection<MetadataConversionError> errors = new Collection<MetadataConversionError> ();
 		Collection<MetadataConversionError> errors = new Collection<MetadataConversionError> ();
+		Dictionary<Object,Object> state = new Dictionary<Object, Object> ();
 
 
 		internal MetadataImporter (IEnumerable<IPolicyImportExtension> policyImportExtensions)
 		internal MetadataImporter (IEnumerable<IPolicyImportExtension> policyImportExtensions)
 		{
 		{
@@ -65,7 +66,7 @@ namespace System.ServiceModel.Description
 		}
 		}
 
 
 		public Dictionary<Object,Object> State {
 		public Dictionary<Object,Object> State {
-			get { throw new NotImplementedException (); }
+			get { return state; }
 		}
 		}
 
 
 		public Dictionary<XmlQualifiedName,ContractDescription> KnownContracts {
 		public Dictionary<XmlQualifiedName,ContractDescription> KnownContracts {
@@ -75,5 +76,15 @@ namespace System.ServiceModel.Description
 		public abstract Collection<ContractDescription> ImportAllContracts ();
 		public abstract Collection<ContractDescription> ImportAllContracts ();
 
 
 		public abstract ServiceEndpointCollection ImportAllEndpoints ();
 		public abstract ServiceEndpointCollection ImportAllEndpoints ();
+
+		internal T GetState<T> () where T : class, new ()
+		{
+			object value;
+			if (!state.TryGetValue (typeof(T), out value)) {
+				value = new T ();
+				state.Add (typeof(T), value);
+			}
+			return (T) value;
+		}
 	}
 	}
 }
 }