//
// Author:
// Miguel de Icaza
+// Lluis Sanchez Gual (lluis@ximian.com)
//
// (C) 2003 Ximian, 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.Reflection;
using System.Collections;
+using System.Xml;
using System.Xml.Serialization;
using System.Web.Services;
using System.Web.Services.Description;
// 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;
internal string ResponseName;
internal string ResponseNamespace;
- internal bool OneWay;
+ internal bool OneWay;
internal SoapParameterStyle ParameterStyle;
+ internal SoapBindingStyle SoapBindingStyle;
internal SoapBindingUse Use;
- internal XmlSerializer RequestSerializer;
- internal XmlSerializer ResponseSerializer;
+ 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, SoapDocumentMethodAttribute dma, XmlReflectionImporter importer)
+ 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;
- Use = dma.Use;
- if (Use == SoapBindingUse.Default)
+ if (kind == null) {
Use = parent.Use;
- if (Use != SoapBindingUse.Literal)
- throw new Exception ("Only SoapBindingUse.Literal supported");
-
- OneWay = dma.OneWay;
+ RequestName = "";
+ RequestNamespace = "";
+ ResponseName = "";
+ 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) {
+ if (parent.SoapBindingStyle == SoapBindingStyle.Document)
+ Use = parent.Use;
+ else
+ Use = SoapBindingUse.Literal;
+ }
+
+ Action = dma.Action;
+ Binding = dma.Binding;
+ RequestName = dma.RequestElementName;
+ RequestNamespace = dma.RequestNamespace;
+ ResponseName = dma.ResponseElementName;
+ ResponseNamespace = dma.ResponseNamespace;
+ ParameterStyle = dma.ParameterStyle;
+ 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
+
+ Action = rma.Action;
+ Binding = rma.Binding;
+
+ // 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;
+ 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 ();
+ optional_ns.Namespace = "";
+ }
+
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.");
}
- Action = dma.Action;
- Binding = (dma.Binding == "" ? parent.BindingName : dma.Binding);
- RequestName = dma.RequestElementName;
- if (RequestName == "")
- RequestName = source.Name;
+ BindingInfo binfo = parent.GetBinding (Binding);
+ if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'.");
- RequestNamespace = dma.RequestNamespace;
- ResponseName = dma.ResponseElementName;
- ResponseNamespace = dma.ResponseNamespace;
- ParameterStyle = dma.ParameterStyle;
- if (ParameterStyle == SoapParameterStyle.Default)
- ParameterStyle = parent.ParameterStyle;
+ 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);
- object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
- if (o.Length == 1){
- WebMethodAttribute wma = (WebMethodAttribute) o [0];
+ 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 {
+ soapImporter.IncludeTypes (source.CustomAttributeProvider);
+ InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, writeAccessors);
+ OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, writeAccessors);
+ }
- Name = wma.MessageName;
- if (Name == "")
- Name = source.Name;
- } else
- Name = source.Name;
+ requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
+ responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
- if (ResponseName == "")
- ResponseName = Name + "Response";
+ 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 ();
- MakeRequestSerializer (importer);
- MakeResponseSerializer (importer);
- }
-
- static internal MethodStubInfo Create (TypeStubInfo parent, LogicalMethodInfo lmi, XmlReflectionImporter importer)
- {
- object [] o = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
- if (o.Length == 0){
- lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
- if (o.Length != 0)
- throw new Exception ("SoapRpcMethod not supported, only SoapDocumentMethod");
- return null;
+ 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 + ".");
+
+ 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));
- return new MethodStubInfo (parent, lmi, (SoapDocumentMethodAttribute) o [0], importer);
+ 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);
+ }
+
+ 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);
}
- void MakeRequestSerializer (XmlReflectionImporter importer)
+ XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
{
ParameterInfo [] input = MethodInfo.InParameters;
XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
-
- for (int i = 0; i < input.Length; i++){
+
+ for (int i = 0; i < input.Length; i++)
+ {
XmlReflectionMember m = new XmlReflectionMember ();
m.IsReturnValue = false;
m.MemberName = input [i].Name;
m.MemberType = input [i].ParameterType;
+ m.XmlAttributes = new XmlAttributes (input[i]);
+ m.SoapAttributes = new SoapAttributes (input[i]);
+
+ if (m.MemberType.IsByRef)
+ m.MemberType = m.MemberType.GetElementType ();
+ if (optional_ns != null)
+ m.XmlAttributes.XmlElements.Add (optional_ns);
in_members [i] = m;
}
-
- TypeStubInfo.SingleMembersMapping [0] =
- importer.ImportMembersMapping (RequestName, RequestNamespace, in_members, true);
- XmlSerializer [] s = XmlSerializer.FromMappings (TypeStubInfo.SingleMembersMapping);
- RequestSerializer = s [0];
+ return in_members;
}
-
- void MakeResponseSerializer (XmlReflectionImporter importer)
+
+ XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
{
ParameterInfo [] output = MethodInfo.OutParameters;
- XmlReflectionMember [] out_members = new XmlReflectionMember [(OneWay ? 0 : 1) + output.Length];
+ bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
+ XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
XmlReflectionMember m;
int idx = 0;
- if (!OneWay){
+ if (has_return_value)
+ {
m = new XmlReflectionMember ();
m.IsReturnValue = true;
m.MemberName = RequestName + "Result";
m.MemberType = MethodInfo.ReturnType;
+
+ m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
+ m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
+
+ if (optional_ns != null)
+ m.XmlAttributes.XmlElements.Add (optional_ns);
idx++;
out_members [0] = m;
}
- for (int i = 0; i < output.Length; i++){
+ for (int i = 0; i < output.Length; i++)
+ {
m = new XmlReflectionMember ();
m.IsReturnValue = false;
m.MemberName = output [i].Name;
m.MemberType = output [i].ParameterType;
+ m.XmlAttributes = new XmlAttributes (output[i]);
+ m.SoapAttributes = new SoapAttributes (output[i]);
if (m.MemberType.IsByRef)
m.MemberType = m.MemberType.GetElementType ();
+ if (optional_ns != null)
+ m.XmlAttributes.XmlElements.Add (optional_ns);
out_members [i + idx] = m;
}
+ return out_members;
+ }
+
+ XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers)
+ {
+ XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length];
- TypeStubInfo.SingleMembersMapping [0] =
- importer.ImportMembersMapping (RequestName, RequestNamespace, out_members, true);
- XmlSerializer [] s = XmlSerializer.FromMappings (TypeStubInfo.SingleMembersMapping);
- ResponseSerializer = s [0];
+ 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
+ {
+ internal MemberInfo Member;
+ internal SoapHeaderAttribute AttributeInfo;
+ internal Type HeaderType;
+ internal bool IsUnknownHeader;
+
+ public HeaderInfo (MemberInfo member, SoapHeaderAttribute attributeInfo)
+ {
+ Member = member;
+ 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)
+ {
+ if (Member is PropertyInfo) return ((PropertyInfo)Member).GetValue (ob, null);
+ else return ((FieldInfo)Member).GetValue (ob);
+ }
+
+ 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; }
+ }
+ }
+
+
//
// 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 ();
+ 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 string BindingLocation;
- internal string BindingName;
- internal string BindingNamespace;
-
- // We only use this to avoid creating tons of arrays that are barely used.
- internal static XmlMembersMapping [] SingleMembersMapping = new XmlMembersMapping [1];
-
- void GetTypeAttributes (Type t)
+ internal SoapExtensionRuntimeConfig[][] SoapExtensions;
+ internal SoapBindingStyle SoapBindingStyle;
+ internal XmlReflectionImporter xmlImporter;
+ internal SoapReflectionImporter soapImporter;
+
+ public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
+ : base (logicalTypeInfo)
{
+ xmlImporter = new XmlReflectionImporter ();
+ soapImporter = new SoapReflectionImporter ();
+
object [] o;
- o = t.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
- if (o.Length != 1)
- throw new Exception ("Expected WebServiceBindingAttribute on "+ t.Name);
- WebServiceBindingAttribute b = (WebServiceBindingAttribute) o [0];
- BindingLocation = b.Location;
- BindingName = b.Name;
- BindingNamespace = b.Namespace;
-
- o = t.GetCustomAttributes (typeof (WebService), 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 {
- ParameterStyle = SoapParameterStyle.Wrapped;
- RoutingStyle = SoapServiceRoutingStyle.SoapAction;
- Use = SoapBindingUse.Literal;
+ o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
+ if (o.Length == 1){
+ SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
+
+ ParameterStyle = SoapParameterStyle.Wrapped;
+ RoutingStyle = srs.RoutingStyle;
+ Use = SoapBindingUse.Encoded;
+ SoapBindingStyle = SoapBindingStyle.Rpc;
+ } else {
+ ParameterStyle = SoapParameterStyle.Wrapped;
+ RoutingStyle = SoapServiceRoutingStyle.SoapAction;
+ Use = SoapBindingUse.Literal;
+ SoapBindingStyle = SoapBindingStyle.Document;
+ }
}
+
+ if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
+ if (Use == SoapBindingUse.Default) Use = SoapBindingUse.Literal;
+
+ xmlImporter.IncludeTypes (Type);
+ soapImporter.IncludeTypes (Type);
- //
- // Some validation
- //
- o = t.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
- if (o.Length != 0)
- throw new Exception ("We do not support SoapRpcService encoding, Type=" + t.Name);
+ SoapExtensions = SoapExtension.GetTypeExtensions (Type);
}
- //
- // Extract all method information
- //
- void GetTypeMethods (Type t, XmlReflectionImporter importer)
+ public override XmlReflectionImporter XmlImporter
{
- 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, importer);
-
- if (msi == null)
- continue;
-
- name_to_method [msi.Name] = msi;
- }
+ get { return xmlImporter; }
}
-
- internal TypeStubInfo (Type t)
- {
- GetTypeAttributes (t);
- XmlReflectionImporter importer = new XmlReflectionImporter ();
- GetTypeMethods (t, importer);
- }
-
- internal MethodStubInfo GetMethod (string name)
+ public override SoapReflectionImporter SoapImporter
{
- return (MethodStubInfo) name_to_method [name];
+ get { return soapImporter; }
}
- }
-
- //
- // Manages
- //
- internal class TypeStubManager {
- static Hashtable type_to_manager;
- static TypeStubManager ()
+ public override string ProtocolName
{
- type_to_manager = new Hashtable ();
+ get { return "Soap"; }
}
-
- //
- // This needs to be thread safe
- //
- static internal TypeStubInfo GetTypeStub (Type t)
+
+ protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
{
- TypeStubInfo tm = (TypeStubInfo) type_to_manager [t];
-
- if (tm != null)
- return tm;
-
- lock (typeof (TypeStubInfo)){
- tm = (TypeStubInfo) type_to_manager [t];
+ SoapMethodStubInfo res = null;
+ object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
+ if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
- if (tm != null)
- return tm;
+ 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);
- tm = new TypeStubInfo (t);
- type_to_manager [t] = tm;
-
- return tm;
- }
+ methods_byaction [res.Action] = res;
+ return res;
+ }
+
+ public SoapMethodStubInfo GetMethodForSoapAction (string name)
+ {
+ return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];
}
}
}