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 XmlSerializer RequestSerializer;
46 internal XmlSerializer ResponseSerializer;
48 internal HeaderInfo[] Headers;
50 internal SoapExtensionRuntimeConfig[] SoapExtensions;
52 private XmlMembersMapping[] _membersMapping;
54 internal XmlMembersMapping InputMembersMapping
56 get { return _membersMapping[0]; }
59 internal XmlMembersMapping OutputMembersMapping
61 get { return _membersMapping[1]; }
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 = parent.WebServiceNamespace;
78 ResponseNamespace = parent.WebServiceNamespace;
79 ParameterStyle = parent.ParameterStyle;
80 SoapBindingStyle = parent.SoapBindingStyle;
83 else if (kind is SoapDocumentMethodAttribute){
84 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
87 if (Use == SoapBindingUse.Default)
91 Binding = dma.Binding;
92 RequestName = dma.RequestElementName;
93 RequestNamespace = dma.RequestNamespace;
94 ResponseName = dma.ResponseElementName;
95 ResponseNamespace = dma.ResponseNamespace;
96 ParameterStyle = dma.ParameterStyle;
97 if (ParameterStyle == SoapParameterStyle.Default)
98 ParameterStyle = parent.ParameterStyle;
100 SoapBindingStyle = SoapBindingStyle.Document;
102 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
103 Use = SoapBindingUse.Encoded; // RPC always use encoded
106 Binding = rma.Binding;
107 RequestName = rma.RequestElementName;
108 RequestNamespace = rma.RequestNamespace;
109 ResponseNamespace = rma.ResponseNamespace;
110 ResponseName = rma.ResponseElementName;
111 ParameterStyle = SoapParameterStyle.Wrapped;
113 SoapBindingStyle = SoapBindingStyle.Rpc;
115 // For RPC calls, make all arguments be part of the empty namespace
116 optional_ns = new XmlElementAttribute ();
117 optional_ns.Namespace = "";
121 if (source.ReturnType != typeof (void))
122 throw new Exception ("OneWay methods should not have a return value");
123 if (source.OutParameters.Length != 0)
124 throw new Exception ("OneWay methods should not have out/ref parameters");
127 if (RequestNamespace == "") RequestNamespace = parent.WebServiceNamespace;
128 if (ResponseNamespace == "") ResponseNamespace = parent.WebServiceNamespace;
129 if (RequestName == "") RequestName = Name;
130 if (ResponseName == "") ResponseName = Name + "Response";
131 if (Binding == null || Binding == "") Binding = parent.DefaultBinding;
132 else if (parent.GetBinding (Binding) == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'");
134 if (Action == null || Action == "")
135 Action = RequestNamespace.EndsWith("/") ? (RequestNamespace + Name) : (RequestNamespace + "/" + Name);
137 bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
139 XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
140 XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
142 _membersMapping = new XmlMembersMapping [2];
144 if (Use == SoapBindingUse.Literal) {
145 _membersMapping [0] = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem);
146 _membersMapping [1] = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem);
149 _membersMapping [0] = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, true);
150 _membersMapping [1] = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, true);
153 XmlSerializer [] s = null;
154 s = XmlSerializer.FromMappings (_membersMapping);
155 RequestSerializer = s [0];
156 ResponseSerializer = s [1];
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);
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;
294 public XmlNode detail;
298 // Holds the metadata loaded from the type stub, as well as
299 // the metadata for all the methods in the type
301 internal class SoapTypeStubInfo : TypeStubInfo
303 Hashtable header_serializers = new Hashtable ();
304 Hashtable header_serializers_byname = new Hashtable ();
307 internal SoapParameterStyle ParameterStyle;
308 internal SoapServiceRoutingStyle RoutingStyle;
309 internal SoapBindingUse Use;
310 internal XmlSerializer FaultSerializer;
311 internal SoapExtensionRuntimeConfig[][] SoapExtensions;
312 internal SoapBindingStyle SoapBindingStyle;
313 internal XmlReflectionImporter xmlImporter;
314 internal SoapReflectionImporter soapImporter;
316 public SoapTypeStubInfo (Type t)
319 xmlImporter = new XmlReflectionImporter ();
320 soapImporter = new SoapReflectionImporter ();
324 o = t.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
325 foreach (WebServiceBindingAttribute at in o)
326 Bindings.Add (new BindingInfo (at, WebServiceNamespace));
328 o = t.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
330 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
332 ParameterStyle = a.ParameterStyle;
333 RoutingStyle = a.RoutingStyle;
335 SoapBindingStyle = SoapBindingStyle.Document;
337 o = t.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
339 SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
341 ParameterStyle = SoapParameterStyle.Wrapped;
342 RoutingStyle = srs.RoutingStyle;
343 Use = SoapBindingUse.Encoded;
344 SoapBindingStyle = SoapBindingStyle.Rpc;
346 ParameterStyle = SoapParameterStyle.Wrapped;
347 RoutingStyle = SoapServiceRoutingStyle.SoapAction;
348 Use = SoapBindingUse.Literal;
349 SoapBindingStyle = SoapBindingStyle.Document;
353 if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
354 if (Use == SoapBindingUse.Default) Use = SoapBindingUse.Literal;
356 FaultSerializer = new XmlSerializer (typeof(Fault));
357 SoapExtensions = SoapExtension.GetTypeExtensions (t);
360 public override XmlReflectionImporter XmlImporter
362 get { return xmlImporter; }
365 public override SoapReflectionImporter SoapImporter
367 get { return soapImporter; }
370 public override string ProtocolName
372 get { return "Soap"; }
375 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
377 object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
378 if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
380 if (ats.Length == 0 && isClientProxy)
382 else if (ats.Length == 0)
383 return new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
385 return new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
388 internal void RegisterHeaderType (Type type)
390 XmlSerializer s = (XmlSerializer) header_serializers [type];
391 if (s != null) return;
393 XmlReflectionImporter ri = new XmlReflectionImporter ();
394 XmlTypeMapping tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
395 s = new XmlSerializer (tm);
397 header_serializers [type] = s;
398 header_serializers_byname [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = s;
401 internal XmlSerializer GetHeaderSerializer (Type type)
403 return (XmlSerializer) header_serializers [type];
406 internal XmlSerializer GetHeaderSerializer (XmlQualifiedName qname)
408 return (XmlSerializer) header_serializers_byname [qname];