2 // Methods.cs: Information about a method and its mapping to a SOAP web service.
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // (C) 2003 Ximian, Inc.
14 using System.Reflection;
15 using System.Collections;
17 using System.Xml.Serialization;
18 using System.Web.Services;
19 using System.Web.Services.Description;
21 namespace System.Web.Services.Protocols {
24 // This class represents all the information we extract from a MethodInfo
25 // in the SoapHttpClientProtocol derivative stub class
27 internal class SoapMethodStubInfo : MethodStubInfo
29 internal string Action;
30 internal string Binding;
32 // The name/namespace of the request
33 internal string RequestName;
34 internal string RequestNamespace;
36 // The name/namespace of the response.
37 internal string ResponseName;
38 internal string ResponseNamespace;
41 internal SoapParameterStyle ParameterStyle;
42 internal SoapBindingStyle SoapBindingStyle;
43 internal SoapBindingUse Use;
45 internal HeaderInfo[] Headers;
46 internal SoapExtensionRuntimeConfig[] SoapExtensions;
48 internal XmlMembersMapping InputMembersMapping;
49 internal XmlMembersMapping OutputMembersMapping;
51 private int requestSerializerId;
52 private int responseSerializerId;
54 internal XmlSerializer RequestSerializer
56 get { return TypeStub.GetSerializer (requestSerializerId); }
59 internal XmlSerializer ResponseSerializer
61 get { return TypeStub.GetSerializer (responseSerializerId); }
67 public SoapMethodStubInfo (TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
68 : base (typeStub, source)
70 SoapTypeStubInfo parent = (SoapTypeStubInfo) typeStub;
71 XmlElementAttribute optional_ns = null;
76 RequestNamespace = "";
78 ResponseNamespace = "";
79 ParameterStyle = parent.ParameterStyle;
80 SoapBindingStyle = parent.SoapBindingStyle;
83 else if (kind is SoapDocumentMethodAttribute){
84 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
87 if (Use == SoapBindingUse.Default) {
88 if (parent.SoapBindingStyle == SoapBindingStyle.Document)
91 Use = SoapBindingUse.Literal;
95 Binding = dma.Binding;
96 RequestName = dma.RequestElementName;
97 RequestNamespace = dma.RequestNamespace;
98 ResponseName = dma.ResponseElementName;
99 ResponseNamespace = dma.ResponseNamespace;
100 ParameterStyle = dma.ParameterStyle;
101 if (ParameterStyle == SoapParameterStyle.Default)
102 ParameterStyle = parent.ParameterStyle;
104 SoapBindingStyle = SoapBindingStyle.Document;
106 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
107 Use = SoapBindingUse.Encoded; // RPC always use encoded
110 Binding = rma.Binding;
111 RequestName = rma.RequestElementName;
112 RequestNamespace = rma.RequestNamespace;
113 ResponseNamespace = rma.ResponseNamespace;
114 ResponseName = rma.ResponseElementName;
115 ParameterStyle = SoapParameterStyle.Wrapped;
117 SoapBindingStyle = SoapBindingStyle.Rpc;
119 // For RPC calls, make all arguments be part of the empty namespace
120 optional_ns = new XmlElementAttribute ();
121 optional_ns.Namespace = "";
125 if (source.ReturnType != typeof (void))
126 throw new Exception ("OneWay methods should not have a return value");
127 if (source.OutParameters.Length != 0)
128 throw new Exception ("OneWay methods should not have out/ref parameters");
131 if (RequestNamespace == "") RequestNamespace = parent.LogicalType.GetWebServiceNamespace (Use);
132 if (ResponseNamespace == "") ResponseNamespace = parent.LogicalType.GetWebServiceNamespace (Use);
133 if (RequestName == "") RequestName = Name;
134 if (ResponseName == "") ResponseName = Name + "Response";
135 if (Binding == null || Binding == "") Binding = parent.DefaultBinding;
136 else if (parent.GetBinding (Binding) == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'");
138 if (Action == null || Action == "")
139 Action = RequestNamespace.EndsWith("/") ? (RequestNamespace + Name) : (RequestNamespace + "/" + Name);
141 bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
143 XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
144 XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
146 if (Use == SoapBindingUse.Literal) {
147 InputMembersMapping = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem);
148 OutputMembersMapping = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem);
151 InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, true);
152 OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, true);
155 requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
156 responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
158 object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
159 Headers = new HeaderInfo[o.Length];
160 for (int i = 0; i < o.Length; i++) {
161 SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
162 MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
163 if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName);
165 Type headerType = (mems[0] is FieldInfo) ? ((FieldInfo)mems[0]).FieldType : ((PropertyInfo)mems[0]).PropertyType;
166 Headers [i] = new HeaderInfo (mems[0], att);
167 parent.RegisterHeaderType (headerType, Use);
170 SoapExtensions = SoapExtension.GetMethodExtensions (source);
173 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
175 ParameterInfo [] input = MethodInfo.InParameters;
176 XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
178 for (int i = 0; i < input.Length; i++)
180 XmlReflectionMember m = new XmlReflectionMember ();
181 m.IsReturnValue = false;
182 m.MemberName = input [i].Name;
183 m.MemberType = input [i].ParameterType;
185 m.XmlAttributes = new XmlAttributes (input[i]);
186 m.SoapAttributes = new SoapAttributes (input[i]);
188 if (m.MemberType.IsByRef)
189 m.MemberType = m.MemberType.GetElementType ();
190 if (optional_ns != null)
191 m.XmlAttributes.XmlElements.Add (optional_ns);
197 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
199 ParameterInfo [] output = MethodInfo.OutParameters;
200 bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
201 XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
202 XmlReflectionMember m;
205 if (has_return_value)
207 m = new XmlReflectionMember ();
208 m.IsReturnValue = true;
209 m.MemberName = RequestName + "Result";
210 m.MemberType = MethodInfo.ReturnType;
212 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
213 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
215 if (optional_ns != null)
216 m.XmlAttributes.XmlElements.Add (optional_ns);
221 for (int i = 0; i < output.Length; i++)
223 m = new XmlReflectionMember ();
224 m.IsReturnValue = false;
225 m.MemberName = output [i].Name;
226 m.MemberType = output [i].ParameterType;
227 m.XmlAttributes = new XmlAttributes (output[i]);
228 m.SoapAttributes = new SoapAttributes (output[i]);
230 if (m.MemberType.IsByRef)
231 m.MemberType = m.MemberType.GetElementType ();
232 if (optional_ns != null)
233 m.XmlAttributes.XmlElements.Add (optional_ns);
234 out_members [i + idx] = m;
239 public HeaderInfo GetHeaderInfo (Type headerType)
241 foreach (HeaderInfo headerInfo in Headers)
242 if (headerInfo.HeaderType == headerType) return headerInfo;
247 internal class HeaderInfo
249 internal MemberInfo Member;
250 internal SoapHeaderAttribute AttributeInfo;
251 internal Type HeaderType;
253 public HeaderInfo (MemberInfo member, SoapHeaderAttribute attributeInfo)
256 AttributeInfo = attributeInfo;
257 if (Member is PropertyInfo) HeaderType = ((PropertyInfo)Member).PropertyType;
258 else HeaderType = ((FieldInfo)Member).FieldType;
261 public object GetHeaderValue (object ob)
263 if (Member is PropertyInfo) return ((PropertyInfo)Member).GetValue (ob, null);
264 else return ((FieldInfo)Member).GetValue (ob);
267 public void SetHeaderValue (object ob, object value)
269 if (Member is PropertyInfo) ((PropertyInfo)Member).SetValue (ob, value, null);
270 else ((FieldInfo)Member).SetValue (ob, value);
273 public SoapHeaderDirection Direction
275 get { return AttributeInfo.Direction; }
283 public Fault (SoapException ex)
286 faultstring = ex.Message;
287 faultactor = ex.Actor;
291 public XmlQualifiedName faultcode;
292 public string faultstring;
293 public string faultactor;
296 public XmlNode detail;
300 // Holds the metadata loaded from the type stub, as well as
301 // the metadata for all the methods in the type
303 internal class SoapTypeStubInfo : TypeStubInfo
305 Hashtable[] header_serializers = new Hashtable [3];
306 Hashtable[] header_serializers_byname = new Hashtable [3];
309 internal SoapParameterStyle ParameterStyle;
310 internal SoapServiceRoutingStyle RoutingStyle;
311 internal SoapBindingUse Use;
312 internal int faultSerializerLitId = -1;
313 internal int faultSerializerEncId = -1;
314 internal SoapExtensionRuntimeConfig[][] SoapExtensions;
315 internal SoapBindingStyle SoapBindingStyle;
316 internal XmlReflectionImporter xmlImporter;
317 internal SoapReflectionImporter soapImporter;
319 public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
320 : base (logicalTypeInfo)
322 xmlImporter = new XmlReflectionImporter ();
323 soapImporter = new SoapReflectionImporter ();
327 o = Type.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
328 foreach (WebServiceBindingAttribute at in o)
329 Bindings.Add (new BindingInfo (at, LogicalType.WebServiceNamespace));
331 o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
333 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
335 ParameterStyle = a.ParameterStyle;
336 RoutingStyle = a.RoutingStyle;
338 SoapBindingStyle = SoapBindingStyle.Document;
340 o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
342 SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
344 ParameterStyle = SoapParameterStyle.Wrapped;
345 RoutingStyle = srs.RoutingStyle;
346 Use = SoapBindingUse.Encoded;
347 SoapBindingStyle = SoapBindingStyle.Rpc;
349 ParameterStyle = SoapParameterStyle.Wrapped;
350 RoutingStyle = SoapServiceRoutingStyle.SoapAction;
351 Use = SoapBindingUse.Literal;
352 SoapBindingStyle = SoapBindingStyle.Document;
356 if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
357 if (Use == SoapBindingUse.Default) Use = SoapBindingUse.Literal;
359 SoapExtensions = SoapExtension.GetTypeExtensions (Type);
362 public override XmlReflectionImporter XmlImporter
364 get { return xmlImporter; }
367 public override SoapReflectionImporter SoapImporter
369 get { return soapImporter; }
372 public override string ProtocolName
374 get { return "Soap"; }
377 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
379 SoapMethodStubInfo res = null;
380 object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
381 if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
383 if (ats.Length == 0 && isClientProxy)
385 else if (ats.Length == 0)
386 res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
388 res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
390 if (faultSerializerEncId == -1 && res.Use == SoapBindingUse.Encoded)
392 SoapReflectionImporter ri = new SoapReflectionImporter ();
393 XmlTypeMapping tm = ri.ImportTypeMapping (typeof(Fault));
394 faultSerializerEncId = RegisterSerializer (tm);
396 else if (faultSerializerLitId == -1 && res.Use == SoapBindingUse.Literal)
398 XmlReflectionImporter ri = new XmlReflectionImporter ();
399 XmlTypeMapping tm = ri.ImportTypeMapping (typeof(Fault));
400 faultSerializerLitId = RegisterSerializer (tm);
405 public XmlSerializer GetFaultSerializer (SoapBindingUse use)
407 if (use == SoapBindingUse.Literal)
408 return GetSerializer (faultSerializerLitId);
410 return GetSerializer (faultSerializerEncId);
413 internal void RegisterHeaderType (Type type, SoapBindingUse use)
415 Hashtable serializers = header_serializers [(int)use];
416 if (serializers == null) {
417 serializers = new Hashtable ();
418 header_serializers [(int)use] = serializers;
419 header_serializers_byname [(int)use] = new Hashtable ();
422 if (serializers.ContainsKey (type))
426 if (use == SoapBindingUse.Literal) {
427 XmlReflectionImporter ri = new XmlReflectionImporter ();
428 tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
431 SoapReflectionImporter ri = new SoapReflectionImporter ();
432 tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
435 int sid = RegisterSerializer (tm);
437 serializers [type] = sid;
438 header_serializers_byname [(int)use] [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = sid;
441 internal XmlSerializer GetHeaderSerializer (Type type, SoapBindingUse use)
443 Hashtable table = header_serializers [(int)use];
444 if (table == null) return null;
446 return GetSerializer ((int) table [type]);
449 internal XmlSerializer GetHeaderSerializer (XmlQualifiedName qname, SoapBindingUse use)
451 Hashtable table = header_serializers_byname [(int)use];
452 if (table == null) return null;
454 return GetSerializer ((int) table [qname]);