New test.
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Protocols / Methods.cs
index ee47b71c5b8e3057e7e11a5baa67cbb1d522909b..10a81b8501554be277a2f51f7addd32f5df21fd6 100644 (file)
@@ -7,8 +7,26 @@
 //
 // (C) 2003 Ximian, Inc.
 //
-// TODO:
-//    
+
+//
+// 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.Reflection;
@@ -24,12 +42,8 @@ namespace System.Web.Services.Protocols {
        // This class represents all the information we extract from a MethodInfo
        // in the SoapHttpClientProtocol derivative stub class
        //
-       internal class MethodStubInfo {
-               internal LogicalMethodInfo MethodInfo;
-
-               // The name used bythe stub class to reference this method.
-               internal string Name;
-               
+       internal class SoapMethodStubInfo : MethodStubInfo
+       {
                internal string Action;
                internal string Binding;
 
@@ -41,46 +55,84 @@ namespace System.Web.Services.Protocols {
                internal string ResponseName;
                internal string ResponseNamespace;
                
-               internal bool   OneWay;
+               internal bool OneWay;
                internal SoapParameterStyle ParameterStyle;
-
-               internal bool BufferResponse;
-               internal int CacheDuration;
-               internal string Description;
-               internal bool EnableSession;
-
-               internal XmlSerializer RequestSerializer;
-               internal XmlSerializer ResponseSerializer;
+               internal SoapBindingStyle SoapBindingStyle;
+               internal SoapBindingUse Use;
 
                internal HeaderInfo[] Headers;
-
+               internal HeaderInfo[] InHeaders;
+               internal HeaderInfo[] OutHeaders;
+               internal HeaderInfo[] FaultHeaders;
                internal SoapExtensionRuntimeConfig[] SoapExtensions;
+               
+               internal XmlMembersMapping InputMembersMapping;
+               internal XmlMembersMapping OutputMembersMapping;
+               internal XmlMembersMapping InputHeaderMembersMapping;
+               internal XmlMembersMapping OutputHeaderMembersMapping;
+               internal XmlMembersMapping FaultHeaderMembersMapping;
+               
+               private int requestSerializerId;
+               private int responseSerializerId;
+               private int requestHeadersSerializerId = -1;
+               private int responseHeadersSerializerId = -1;
+               private int faultHeadersSerializerId = -1;
+               
+               internal XmlSerializer RequestSerializer
+               {
+                       get { return TypeStub.GetSerializer (requestSerializerId); }
+               }
+               
+               internal XmlSerializer ResponseSerializer
+               {
+                       get { return TypeStub.GetSerializer (responseSerializerId); }
+               }
+               
+               internal XmlSerializer RequestHeadersSerializer
+               {
+                       get { return requestHeadersSerializerId != -1 ? TypeStub.GetSerializer (requestHeadersSerializerId) : null; }
+               }
+               
+               internal XmlSerializer ResponseHeadersSerializer
+               {
+                       get { return responseHeadersSerializerId != -1 ? TypeStub.GetSerializer (responseHeadersSerializerId) : null; }
+               }
+               
+               internal XmlSerializer FaultHeadersSerializer
+               {
+                       get { return faultHeadersSerializerId != -1 ? TypeStub.GetSerializer (faultHeadersSerializerId) : null; }
+               }
+               
 
                //
                // Constructor
                //
-               MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
+               public SoapMethodStubInfo (TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
+               : base (typeStub, source)
                {
-                       MethodInfo = source;
-
+                       SoapTypeStubInfo parent = (SoapTypeStubInfo) typeStub;
                        XmlElementAttribute optional_ns = null;
-                       SoapBindingUse use;
 
                        if (kind == null) {
-                               use = parent.Use;
+                               Use = parent.Use;
                                RequestName = "";
-                               RequestNamespace = parent.WebServiceNamespace;
+                               RequestNamespace = "";
                                ResponseName = "";
-                               ResponseNamespace = parent.WebServiceNamespace;
+                               ResponseNamespace = "";
                                ParameterStyle = parent.ParameterStyle;
+                               SoapBindingStyle = parent.SoapBindingStyle;
                                OneWay = false;
                        }
                        else if (kind is SoapDocumentMethodAttribute){
                                SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
                                
-                               use = dma.Use;
-                               if (use == SoapBindingUse.Default)
-                                       use = parent.Use;
+                               Use = dma.Use;
+                               if (Use == SoapBindingUse.Default) {
+                                       if (parent.SoapBindingStyle == SoapBindingStyle.Document)
+                                               Use = parent.Use;
+                                       else
+                                               Use = SoapBindingUse.Literal;
+                               }
                                
                                Action = dma.Action;
                                Binding = dma.Binding;
@@ -92,17 +144,25 @@ namespace System.Web.Services.Protocols {
                                if (ParameterStyle == SoapParameterStyle.Default)
                                        ParameterStyle = parent.ParameterStyle;
                                OneWay = dma.OneWay;
+                               SoapBindingStyle = SoapBindingStyle.Document;
                        } else {
                                SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
-                               use = SoapBindingUse.Encoded;   // RPC always use encoded
+                               Use = SoapBindingUse.Encoded;   // RPC always use encoded
 
                                Action = rma.Action;
                                Binding = rma.Binding;
-                               RequestName = rma.RequestElementName;
+                               
+                               // When using RPC, MS.NET seems to ignore RequestElementName and
+                               // MessageName, and it always uses the method name
+                               RequestName = source.Name;
+                               ResponseName = source.Name + "Response";
+//                             RequestName = rma.RequestElementName;
+//                             ResponseName = rma.ResponseElementName;
                                RequestNamespace = rma.RequestNamespace;
                                ResponseNamespace = rma.ResponseNamespace;
-                               ResponseName = rma.ResponseElementName;
+                               ParameterStyle = SoapParameterStyle.Wrapped;
                                OneWay = rma.OneWay;
+                               SoapBindingStyle = SoapBindingStyle.Rpc;
 
                                // For RPC calls, make all arguments be part of the empty namespace
                                optional_ns = new XmlElementAttribute ();
@@ -111,77 +171,108 @@ namespace System.Web.Services.Protocols {
 
                        if (OneWay){
                                if (source.ReturnType != typeof (void))
-                                       throw new Exception ("OneWay methods should not have a return value");
+                                       throw new Exception ("OneWay methods should not have a return value.");
                                if (source.OutParameters.Length != 0)
-                                       throw new Exception ("OneWay methods should not have out/ref parameters");
+                                       throw new Exception ("OneWay methods should not have out/ref parameters.");
                        }
                        
-                       object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
-                       if (o.Length == 1){
-                               WebMethodAttribute wma = (WebMethodAttribute) o [0];
-                               BufferResponse = wma.BufferResponse;
-                               CacheDuration = wma.CacheDuration;
-                               Description = wma.Description;
-                               EnableSession = wma.EnableSession;
-                               Name = wma.MessageName;
-
-                               if (Name == "")
-                                       Name = source.Name;
-                       } else
-                               Name = source.Name;
-
-                       if (RequestName == "")
-                               RequestName = Name;
-
-                       if (ResponseName == "")
-                               ResponseName = Name + "Response";
-
+                       BindingInfo binfo = parent.GetBinding (Binding);
+                       if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'.");
+                       
+                       string serviceNamespace = binfo.Namespace;
+                               
+                       if (RequestNamespace == "") RequestNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use);
+                       if (ResponseNamespace == "") ResponseNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use);
+                       if (RequestName == "") RequestName = Name;
+                       if (ResponseName == "") ResponseName = Name + "Response";
+                       if (Action == null || Action == "")
+                               Action = serviceNamespace.EndsWith("/") ? (serviceNamespace + Name) : (serviceNamespace + "/" + Name);
+                       
+                       bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
+                       bool writeAccessors = (SoapBindingStyle == SoapBindingStyle.Rpc);
+                       
                        XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
                        XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
 
-                       XmlMembersMapping [] members = new XmlMembersMapping [2];
-
-                       if (use == SoapBindingUse.Literal) {
-                               members [0] = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true);
-                               members [1] = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true);
+                       if (Use == SoapBindingUse.Literal) {
+                               xmlImporter.IncludeTypes (source.CustomAttributeProvider);
+                               InputMembersMapping = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem);
+                               OutputMembersMapping = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem);
                        }
                        else {
-                               members [0] = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true, true);
-                               members [1] = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true, true);
+                               soapImporter.IncludeTypes (source.CustomAttributeProvider);
+                               InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, writeAccessors);
+                               OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, writeAccessors);
                        }
 
-                       XmlSerializer [] s = null;
-                       s = XmlSerializer.FromMappings (members);
-                       RequestSerializer = s [0];
-                       ResponseSerializer = s [1];
+                       requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
+                       responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
 
-                       o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
-                       Headers = new HeaderInfo[o.Length];
+                       object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
+                       ArrayList allHeaderList = new ArrayList (o.Length);
+                       ArrayList inHeaderList = new ArrayList (o.Length);
+                       ArrayList outHeaderList = new ArrayList (o.Length);
+                       ArrayList faultHeaderList = new ArrayList ();
+                       
+                       SoapHeaderDirection unknownHeaderDirections = (SoapHeaderDirection)0;
+                       
                        for (int i = 0; i < o.Length; i++) {
                                SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
                                MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
-                               if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName);
+                               if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + ".");
                                
-                               Type headerType = (mems[0] is FieldInfo) ? ((FieldInfo)mems[0]).FieldType : ((PropertyInfo)mems[0]).PropertyType;
-                               Headers [i] = new HeaderInfo (mems[0], att);
-                               parent.RegisterHeaderType (headerType);
+                               HeaderInfo header = new HeaderInfo (mems[0], att);
+                               allHeaderList.Add (header);
+                               if (!header.IsUnknownHeader) {
+                                       if ((header.Direction & SoapHeaderDirection.In) != 0)
+                                               inHeaderList.Add (header);
+                                       if ((header.Direction & SoapHeaderDirection.Out) != 0)
+                                               outHeaderList.Add (header);
+                                       if ((header.Direction & SoapHeaderDirection.Fault) != 0)
+                                               faultHeaderList.Add (header);
+                               } else
+                                       unknownHeaderDirections |= header.Direction;
                        }
+                       
+                       Headers = (HeaderInfo[]) allHeaderList.ToArray (typeof(HeaderInfo));
 
-                       SoapExtensions = SoapExtension.GetMethodExtensions (source);
-               }
-
-               static internal MethodStubInfo Create (TypeStubInfo parent, LogicalMethodInfo lmi, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
-               {
-                       object [] o = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
-                       if (o.Length == 0) o = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
-
-                       if (o.Length == 0)
-                       {
-                               if (lmi.GetCustomAttributes (typeof (WebMethodAttribute)).Length == 0) return null;
-                               return new MethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
+                       if (inHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.In) != 0) {
+                               InHeaders = (HeaderInfo[]) inHeaderList.ToArray (typeof(HeaderInfo));
+                               XmlReflectionMember[] members = BuildHeadersReflectionMembers (InHeaders);
+                               
+                               if (Use == SoapBindingUse.Literal)
+                                       InputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
+                               else
+                                       InputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
+                               
+                               requestHeadersSerializerId = parent.RegisterSerializer (InputHeaderMembersMapping);
                        }
-                       else
-                               return new MethodStubInfo (parent, lmi, o [0], xmlImporter, soapImporter);
+                       
+                       if (outHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Out) != 0) {
+                               OutHeaders = (HeaderInfo[]) outHeaderList.ToArray (typeof(HeaderInfo));
+                               XmlReflectionMember[] members = BuildHeadersReflectionMembers (OutHeaders);
+                               
+                               if (Use == SoapBindingUse.Literal)
+                                       OutputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
+                               else
+                                       OutputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
+                               
+                               responseHeadersSerializerId = parent.RegisterSerializer (OutputHeaderMembersMapping);
+                       }
+                       
+                       if (faultHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Fault) != 0) {
+                               FaultHeaders = (HeaderInfo[]) faultHeaderList.ToArray (typeof(HeaderInfo));
+                               XmlReflectionMember[] members = BuildHeadersReflectionMembers (FaultHeaders);
+                               
+                               if (Use == SoapBindingUse.Literal)
+                                       FaultHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
+                               else
+                                       FaultHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
+                               
+                               faultHeadersSerializerId = parent.RegisterSerializer (FaultHeaderMembersMapping);
+                       }
+                       
+                       SoapExtensions = SoapExtension.GetMethodExtensions (source);
                }
 
                XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
@@ -250,12 +341,90 @@ namespace System.Web.Services.Protocols {
                        return out_members;
                }
 
+               XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers)
+               {
+                       XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length];
+
+                       for (int n=0; n<headers.Length; n++)
+                       {
+                               HeaderInfo header = headers [n];
+                               
+                               XmlReflectionMember m = new XmlReflectionMember ();
+                               m.IsReturnValue = false;
+                               m.MemberName = header.HeaderType.Name;
+                               m.MemberType = header.HeaderType;
+
+                               // MS.NET reflects header classes in a weird way. The root element
+                               // name is the CLR class name unless it is specified in an XmlRootAttribute.
+                               // The usual is to use the xml type name by default, but not in this case.
+                               
+                               XmlAttributes ats = new XmlAttributes (header.HeaderType);
+                               if (ats.XmlRoot != null) {
+                                       XmlElementAttribute xe = new XmlElementAttribute ();
+                                       xe.ElementName = ats.XmlRoot.ElementName;
+                                       xe.Namespace = ats.XmlRoot.Namespace;
+                                       m.XmlAttributes = new XmlAttributes ();
+                                       m.XmlAttributes.XmlElements.Add (xe);
+                               }
+                               
+                               mems [n] = m;
+                       }
+                       return mems;
+               }
+
                public HeaderInfo GetHeaderInfo (Type headerType)
                {
                        foreach (HeaderInfo headerInfo in Headers)
                                if (headerInfo.HeaderType == headerType) return headerInfo;
                        return null;
                }
+               
+               public XmlSerializer GetBodySerializer (SoapHeaderDirection dir)
+               {
+                       switch (dir) {
+                               case SoapHeaderDirection.In: return RequestSerializer;
+                               case SoapHeaderDirection.Out: return ResponseSerializer;
+                               case SoapHeaderDirection.Fault: return Fault.Serializer;
+                               default: return null;
+                       }
+               }
+               
+               public XmlSerializer GetHeaderSerializer (SoapHeaderDirection dir)
+               {
+                       switch (dir) {
+                               case SoapHeaderDirection.In: return RequestHeadersSerializer;
+                               case SoapHeaderDirection.Out: return ResponseHeadersSerializer;
+                               case SoapHeaderDirection.Fault: return FaultHeadersSerializer;
+                               default: return null;
+                       }
+               }
+               
+               HeaderInfo[] GetHeaders (SoapHeaderDirection dir)
+               {
+                       switch (dir) {
+                               case SoapHeaderDirection.In: return InHeaders;
+                               case SoapHeaderDirection.Out: return OutHeaders;
+                               case SoapHeaderDirection.Fault: return FaultHeaders;
+                               default: return null;
+                       }
+               }
+               
+               public object[] GetHeaderValueArray (SoapHeaderDirection dir, SoapHeaderCollection headers)
+               {
+                       HeaderInfo[] headerInfos = GetHeaders (dir);
+                       if (headerInfos == null) return null;
+
+                       object[] hs = new object [headerInfos.Length];
+                       
+                       for (int n=0; n<headers.Count; n++) {
+                               SoapHeader h = headers[n];
+                               Type t = h.GetType();
+                               for (int i=0; i<headerInfos.Length; i++)
+                                       if (headerInfos [i].HeaderType == t)
+                                               hs [i] = h;
+                       }
+                       return hs;
+               }
        }
 
        internal class HeaderInfo
@@ -263,6 +432,7 @@ namespace System.Web.Services.Protocols {
                internal MemberInfo Member;
                internal SoapHeaderAttribute AttributeInfo;
                internal Type HeaderType;
+               internal bool IsUnknownHeader;
 
                public HeaderInfo (MemberInfo member, SoapHeaderAttribute attributeInfo)
                {
@@ -270,6 +440,14 @@ namespace System.Web.Services.Protocols {
                        AttributeInfo = attributeInfo;
                        if (Member is PropertyInfo) HeaderType = ((PropertyInfo)Member).PropertyType;
                        else HeaderType = ((FieldInfo)Member).FieldType;
+                       
+                       if (HeaderType == typeof(SoapHeader) || HeaderType == typeof(SoapUnknownHeader) ||
+                               HeaderType == typeof(SoapHeader[]) || HeaderType == typeof(SoapUnknownHeader[]))
+                       {
+                               IsUnknownHeader = true;
+                       }
+                       else if (!typeof(SoapHeader).IsAssignableFrom (HeaderType))
+                               throw new InvalidOperationException (string.Format ("Header members type must be a SoapHeader subclass"));
                }
                
                public object GetHeaderValue (object ob)
@@ -278,190 +456,148 @@ namespace System.Web.Services.Protocols {
                        else return ((FieldInfo)Member).GetValue (ob);
                }
 
-               public void SetHeaderValue (object ob, object value)
+               public void SetHeaderValue (object ob, SoapHeader header)
                {
+                       object value = header;
+                       if (IsUnknownHeader && HeaderType.IsArray)
+                       {
+                               SoapUnknownHeader uheader = header as SoapUnknownHeader;
+                               SoapUnknownHeader[] array = (SoapUnknownHeader[]) GetHeaderValue (ob);
+                               if (array == null || array.Length == 0) {
+                                       value = new SoapUnknownHeader[] { uheader };
+                               }
+                               else {
+                                       SoapUnknownHeader[] newArray = new SoapUnknownHeader [array.Length+1];
+                                       Array.Copy (array, newArray, array.Length);
+                                       newArray [array.Length] = uheader;
+                                       value = newArray;
+                               }
+                       }
+                       
                        if (Member is PropertyInfo) ((PropertyInfo)Member).SetValue (ob, value, null);
                        else ((FieldInfo)Member).SetValue (ob, value);
                }
-
+               
                public SoapHeaderDirection Direction
                {
                        get { return AttributeInfo.Direction; }
                }
        }
 
-       internal class Fault
-       {
-               public Fault () {}
-
-               public Fault (SoapException ex) 
-               {
-                       faultcode = ex.Code;
-                       faultstring = ex.Message;
-                       faultactor = ex.Actor;
-                       detail = ex.Detail;
-               }
-
-               public XmlQualifiedName faultcode;
-               public string faultstring;
-               public string faultactor;
-               public XmlNode detail;
-       }
 
        //
        // Holds the metadata loaded from the type stub, as well as
        // the metadata for all the methods in the type
        //
-       internal class TypeStubInfo {
-               Hashtable name_to_method = new Hashtable ();
-               Hashtable header_serializers = new Hashtable ();
-               Hashtable header_serializers_byname = new Hashtable ();
-               Hashtable bindings = new Hashtable ();
+       internal class SoapTypeStubInfo : TypeStubInfo
+       {
+               Hashtable[] header_serializers = new Hashtable [3];
+               Hashtable[] header_serializers_byname = new Hashtable [3];
+               Hashtable methods_byaction = new Hashtable (); 
 
                // Precomputed
                internal SoapParameterStyle      ParameterStyle;
                internal SoapServiceRoutingStyle RoutingStyle;
                internal SoapBindingUse          Use;
-               internal string                  WebServiceName;
-               internal string                  WebServiceNamespace;
-               internal XmlSerializer           FaultSerializer;
                internal SoapExtensionRuntimeConfig[][] SoapExtensions;
+               internal SoapBindingStyle SoapBindingStyle;
+               internal XmlReflectionImporter  xmlImporter;
+               internal SoapReflectionImporter soapImporter;
 
-               void GetTypeAttributes (Type t)
+               public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
+               : base (logicalTypeInfo)
                {
+                       xmlImporter = new XmlReflectionImporter ();
+                       soapImporter = new SoapReflectionImporter ();
+                       
                        object [] o;
 
-                       o = t.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
-
-                       foreach (WebServiceBindingAttribute at in o)
-                               bindings.Add (((WebServiceBindingAttribute)at).Name, at);
-
-                       o = t.GetCustomAttributes (typeof (WebServiceAttribute), false);
-                       if (o.Length == 1){
-                               WebServiceAttribute a = (WebServiceAttribute) o [0];
-
-                               WebServiceName = a.Name;
-                               WebServiceNamespace = a.Namespace;
-                       } else {
-                               WebServiceName = t.Name;
-                               WebServiceNamespace = WebServiceAttribute.DefaultNamespace;
+                       o = Type.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
+                       
+                       if (typeof (SoapHttpClientProtocol).IsAssignableFrom (Type))
+                       {
+                               if (o.Length == 0)
+                                       throw new InvalidOperationException ("WebServiceBindingAttribute is required on proxy class '" + Type + "'.");
+                               if (o.Length > 1)
+                                       throw new InvalidOperationException ("Only one WebServiceBinding attribute may be specified on type '" + Type + "'.");
+                                       
+                               // Remove the default binding, it is not needed since there is always
+                               // a binding attribute.
+                               Bindings.Clear ();
                        }
+                               
+                       foreach (WebServiceBindingAttribute at in o)
+                               AddBinding (new BindingInfo (at, LogicalType.WebServiceNamespace));
 
-                       o = t.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
+                       o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
                        if (o.Length == 1){
                                SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
 
                                ParameterStyle = a.ParameterStyle;
                                RoutingStyle = a.RoutingStyle;
                                Use = a.Use;
+                               SoapBindingStyle = SoapBindingStyle.Document;
                        } else {
-                               o = t.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
+                               o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
                                if (o.Length == 1){
                                        SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
                                        
                                        ParameterStyle = SoapParameterStyle.Wrapped;
                                        RoutingStyle = srs.RoutingStyle;
-                                       Use = SoapBindingUse.Literal;
+                                       Use = SoapBindingUse.Encoded;
+                                       SoapBindingStyle = SoapBindingStyle.Rpc;
                                } else {
                                        ParameterStyle = SoapParameterStyle.Wrapped;
                                        RoutingStyle = SoapServiceRoutingStyle.SoapAction;
                                        Use = SoapBindingUse.Literal;
+                                       SoapBindingStyle = SoapBindingStyle.Document;
                                }
                        }
-                       FaultSerializer = new XmlSerializer (typeof(Fault));
-                       SoapExtensions = SoapExtension.GetTypeExtensions (t);
-               }
-
-               //
-               // Extract all method information
-               //
-               void GetTypeMethods (Type t, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
-               {
-                       MethodInfo [] type_methods = t.GetMethods (BindingFlags.Instance | BindingFlags.Public);
-                       LogicalMethodInfo [] methods = LogicalMethodInfo.Create (type_methods, LogicalMethodTypes.Sync);
-
-                       foreach (LogicalMethodInfo mi in methods){
-                               MethodStubInfo msi = MethodStubInfo.Create (this, mi, xmlImporter, soapImporter);
-
-                               if (msi == null)
-                                       continue;
-
-                               name_to_method [msi.Name] = msi;
-                       }
-               }
-               
-               internal TypeStubInfo (Type t)
-               {
-                       GetTypeAttributes (t);
+                       
+                       if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
+                       if (Use == SoapBindingUse.Default) Use = SoapBindingUse.Literal;
+                       
+                       xmlImporter.IncludeTypes (Type);
+                       soapImporter.IncludeTypes (Type);
 
-                       XmlReflectionImporter xmlImporter = new XmlReflectionImporter ();
-                       SoapReflectionImporter soapImporter = new SoapReflectionImporter ();
-                       GetTypeMethods (t, xmlImporter, soapImporter);
+                       SoapExtensions = SoapExtension.GetTypeExtensions (Type);
                }
 
-               internal MethodStubInfo GetMethod (string name)
+               public override XmlReflectionImporter XmlImporter 
                {
-                       return (MethodStubInfo) name_to_method [name];
+                       get { return xmlImporter; }
                }
 
-
-
-               internal void RegisterHeaderType (Type type)
+               public override SoapReflectionImporter SoapImporter 
                {
-                       XmlSerializer s = (XmlSerializer) header_serializers [type];
-                       if (s != null) return;
-
-                       XmlReflectionImporter ri = new XmlReflectionImporter ();
-                       XmlTypeMapping tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
-                       s = new XmlSerializer (tm);
-
-                       header_serializers [type] = s;
-                       header_serializers_byname [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = s;
+                       get { return soapImporter; }
                }
-
-               internal XmlSerializer GetHeaderSerializer (Type type)
-               {
-                       return (XmlSerializer) header_serializers [type];
-               }
-       
-               internal XmlSerializer GetHeaderSerializer (XmlQualifiedName qname)
+               
+               public override string ProtocolName
                {
-                       return (XmlSerializer) header_serializers_byname [qname];
+                       get { return "Soap"; }
                }
-       }
-       
-       //
-       // Manages 
-       //
-       internal class TypeStubManager {
-               static Hashtable type_to_manager;
                
-               static TypeStubManager ()
+               protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
                {
-                       type_to_manager = new Hashtable ();
+                       SoapMethodStubInfo res = null;
+                       object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
+                       if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
+
+                       if (ats.Length == 0 && isClientProxy)
+                               return null;
+                       else if (ats.Length == 0)
+                               res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
+                       else
+                               res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
+                               
+                       methods_byaction [res.Action] = res;
+                       return res;
                }
-
-               //
-               // This needs to be thread safe
-               //
-               static internal TypeStubInfo GetTypeStub (Type t)
+               
+               public SoapMethodStubInfo GetMethodForSoapAction (string name)
                {
-                       TypeStubInfo tm = (TypeStubInfo) type_to_manager [t];
-
-                       if (tm != null)
-                               return tm;
-
-                       lock (typeof (TypeStubInfo)){
-                               tm = (TypeStubInfo) type_to_manager [t];
-
-                               if (tm != null)
-                                       return tm;
-                               
-                               tm = new TypeStubInfo (t);
-                               type_to_manager [t] = tm;
-
-                               return tm;
-                       }
+                       return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];
                }
        }
 }