* System.Web.Services.dll.sources: Added
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Protocols / Methods.cs
1 //
2 // Methods.cs: Information about a method and its mapping to a SOAP web service.
3 //
4 // Author:
5 //   Miguel de Icaza
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // (C) 2003 Ximian, Inc.
9 //
10 // TODO:
11 //    
12 //
13
14 using System.Reflection;
15 using System.Collections;
16 using System.Xml;
17 using System.Xml.Serialization;
18 using System.Web.Services;
19 using System.Web.Services.Description;
20
21 namespace System.Web.Services.Protocols {
22
23         //
24         // This class represents all the information we extract from a MethodInfo
25         // in the SoapHttpClientProtocol derivative stub class
26         //
27         internal class SoapMethodStubInfo : MethodStubInfo
28         {
29                 internal string Action;
30                 internal string Binding;
31
32                 // The name/namespace of the request 
33                 internal string RequestName;
34                 internal string RequestNamespace;
35
36                 // The name/namespace of the response.
37                 internal string ResponseName;
38                 internal string ResponseNamespace;
39                 
40                 internal bool OneWay;
41                 internal SoapParameterStyle ParameterStyle;
42                 internal SoapBindingStyle SoapBindingStyle;
43                 internal SoapBindingUse Use;
44
45                 internal XmlSerializer RequestSerializer;
46                 internal XmlSerializer ResponseSerializer;
47
48                 internal HeaderInfo[] Headers;
49
50                 internal SoapExtensionRuntimeConfig[] SoapExtensions;
51                 
52                 private XmlMembersMapping[] _membersMapping;
53                 
54                 internal XmlMembersMapping InputMembersMapping
55                 {
56                         get { return _membersMapping[0]; }
57                 }
58
59                 internal XmlMembersMapping OutputMembersMapping
60                 {
61                         get { return _membersMapping[1]; }
62                 }
63
64                 //
65                 // Constructor
66                 //
67                 public SoapMethodStubInfo (TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
68                 : base (typeStub, source)
69                 {
70                         SoapTypeStubInfo parent = (SoapTypeStubInfo) typeStub;
71                         XmlElementAttribute optional_ns = null;
72
73                         if (kind == null) {
74                                 Use = parent.Use;
75                                 RequestName = "";
76                                 RequestNamespace = parent.WebServiceNamespace;
77                                 ResponseName = "";
78                                 ResponseNamespace = parent.WebServiceNamespace;
79                                 ParameterStyle = parent.ParameterStyle;
80                                 SoapBindingStyle = parent.SoapBindingStyle;
81                                 OneWay = false;
82                         }
83                         else if (kind is SoapDocumentMethodAttribute){
84                                 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
85                                 
86                                 Use = dma.Use;
87                                 if (Use == SoapBindingUse.Default)
88                                         Use = parent.Use;
89                                 
90                                 Action = dma.Action;
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;
99                                 OneWay = dma.OneWay;
100                                 SoapBindingStyle = SoapBindingStyle.Document;
101                         } else {
102                                 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
103                                 Use = SoapBindingUse.Encoded;   // RPC always use encoded
104
105                                 Action = rma.Action;
106                                 Binding = rma.Binding;
107                                 RequestName = rma.RequestElementName;
108                                 RequestNamespace = rma.RequestNamespace;
109                                 ResponseNamespace = rma.ResponseNamespace;
110                                 ResponseName = rma.ResponseElementName;
111                                 ParameterStyle = SoapParameterStyle.Wrapped;
112                                 OneWay = rma.OneWay;
113                                 SoapBindingStyle = SoapBindingStyle.Rpc;
114
115                                 // For RPC calls, make all arguments be part of the empty namespace
116                                 optional_ns = new XmlElementAttribute ();
117                                 optional_ns.Namespace = "";
118                         }
119
120                         if (OneWay){
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");
125                         }
126                         
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 + "'");
133                                 
134                         if (Action == null || Action == "")
135                                 Action = RequestNamespace.EndsWith("/") ? (RequestNamespace + Name) : (RequestNamespace + "/" + Name);
136                         
137                         bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
138                         
139                         XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
140                         XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
141
142                         _membersMapping = new XmlMembersMapping [2];
143
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);
147                         }
148                         else {
149                                 _membersMapping [0] = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, true);
150                                 _membersMapping [1] = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, true);
151                         }
152
153                         XmlSerializer [] s = null;
154                         s = XmlSerializer.FromMappings (_membersMapping);
155                         RequestSerializer = s [0];
156                         ResponseSerializer = s [1];
157
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);
164                                 
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);
168                         }
169
170                         SoapExtensions = SoapExtension.GetMethodExtensions (source);
171                 }
172
173                 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
174                 {
175                         ParameterInfo [] input = MethodInfo.InParameters;
176                         XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
177
178                         for (int i = 0; i < input.Length; i++)
179                         {
180                                 XmlReflectionMember m = new XmlReflectionMember ();
181                                 m.IsReturnValue = false;
182                                 m.MemberName = input [i].Name;
183                                 m.MemberType = input [i].ParameterType;
184
185                                 m.XmlAttributes = new XmlAttributes (input[i]);
186                                 m.SoapAttributes = new SoapAttributes (input[i]);
187
188                                 if (m.MemberType.IsByRef)
189                                         m.MemberType = m.MemberType.GetElementType ();
190                                 if (optional_ns != null)
191                                         m.XmlAttributes.XmlElements.Add (optional_ns);
192                                 in_members [i] = m;
193                         }
194                         return in_members;
195                 }
196                 
197                 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
198                 {
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;
203                         int idx = 0;
204
205                         if (has_return_value)
206                         {
207                                 m = new XmlReflectionMember ();
208                                 m.IsReturnValue = true;
209                                 m.MemberName = RequestName + "Result";
210                                 m.MemberType = MethodInfo.ReturnType;
211
212                                 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
213                                 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
214
215                                 if (optional_ns != null)
216                                         m.XmlAttributes.XmlElements.Add (optional_ns);
217                                 idx++;
218                                 out_members [0] = m;
219                         }
220                         
221                         for (int i = 0; i < output.Length; i++)
222                         {
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]);
229
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;
235                         }
236                         return out_members;
237                 }
238
239                 public HeaderInfo GetHeaderInfo (Type headerType)
240                 {
241                         foreach (HeaderInfo headerInfo in Headers)
242                                 if (headerInfo.HeaderType == headerType) return headerInfo;
243                         return null;
244                 }
245         }
246
247         internal class HeaderInfo
248         {
249                 internal MemberInfo Member;
250                 internal SoapHeaderAttribute AttributeInfo;
251                 internal Type HeaderType;
252
253                 public HeaderInfo (MemberInfo member, SoapHeaderAttribute attributeInfo)
254                 {
255                         Member = member;
256                         AttributeInfo = attributeInfo;
257                         if (Member is PropertyInfo) HeaderType = ((PropertyInfo)Member).PropertyType;
258                         else HeaderType = ((FieldInfo)Member).FieldType;
259                 }
260                 
261                 public object GetHeaderValue (object ob)
262                 {
263                         if (Member is PropertyInfo) return ((PropertyInfo)Member).GetValue (ob, null);
264                         else return ((FieldInfo)Member).GetValue (ob);
265                 }
266
267                 public void SetHeaderValue (object ob, object value)
268                 {
269                         if (Member is PropertyInfo) ((PropertyInfo)Member).SetValue (ob, value, null);
270                         else ((FieldInfo)Member).SetValue (ob, value);
271                 }
272
273                 public SoapHeaderDirection Direction
274                 {
275                         get { return AttributeInfo.Direction; }
276                 }
277         }
278
279         internal class Fault
280         {
281                 public Fault () {}
282
283                 public Fault (SoapException ex) 
284                 {
285                         faultcode = ex.Code;
286                         faultstring = ex.Message;
287                         faultactor = ex.Actor;
288                         detail = ex.Detail;
289                 }
290
291                 public XmlQualifiedName faultcode;
292                 public string faultstring;
293                 public string faultactor;
294                 public XmlNode detail;
295         }
296         
297         //
298         // Holds the metadata loaded from the type stub, as well as
299         // the metadata for all the methods in the type
300         //
301         internal class SoapTypeStubInfo : TypeStubInfo
302         {
303                 Hashtable header_serializers = new Hashtable ();
304                 Hashtable header_serializers_byname = new Hashtable ();
305
306                 // Precomputed
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;
315
316                 public SoapTypeStubInfo (Type t)
317                 : base (t)
318                 {
319                         xmlImporter = new XmlReflectionImporter ();
320                         soapImporter = new SoapReflectionImporter ();
321                         
322                         object [] o;
323
324                         o = t.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
325                         foreach (WebServiceBindingAttribute at in o)
326                                 Bindings.Add (new BindingInfo (at, WebServiceNamespace));
327
328                         o = t.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
329                         if (o.Length == 1){
330                                 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
331
332                                 ParameterStyle = a.ParameterStyle;
333                                 RoutingStyle = a.RoutingStyle;
334                                 Use = a.Use;
335                                 SoapBindingStyle = SoapBindingStyle.Document;
336                         } else {
337                                 o = t.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
338                                 if (o.Length == 1){
339                                         SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
340                                         
341                                         ParameterStyle = SoapParameterStyle.Wrapped;
342                                         RoutingStyle = srs.RoutingStyle;
343                                         Use = SoapBindingUse.Encoded;
344                                         SoapBindingStyle = SoapBindingStyle.Rpc;
345                                 } else {
346                                         ParameterStyle = SoapParameterStyle.Wrapped;
347                                         RoutingStyle = SoapServiceRoutingStyle.SoapAction;
348                                         Use = SoapBindingUse.Literal;
349                                         SoapBindingStyle = SoapBindingStyle.Document;
350                                 }
351                         }
352                         
353                         if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
354                         if (Use == SoapBindingUse.Default) Use = SoapBindingUse.Literal;
355
356                         FaultSerializer = new XmlSerializer (typeof(Fault));
357                         SoapExtensions = SoapExtension.GetTypeExtensions (t);
358                 }
359
360                 public override XmlReflectionImporter XmlImporter 
361                 {
362                         get { return xmlImporter; }
363                 }
364
365                 public override SoapReflectionImporter SoapImporter 
366                 {
367                         get { return soapImporter; }
368                 }
369                 
370                 public override string ProtocolName
371                 {
372                         get { return "Soap"; }
373                 }
374                 
375                 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
376                 {
377                         object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
378                         if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
379
380                         if (ats.Length == 0 && isClientProxy)
381                                 return null;
382                         else if (ats.Length == 0)
383                                 return new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
384                         else
385                                 return new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
386                 }
387                 
388                 internal void RegisterHeaderType (Type type)
389                 {
390                         XmlSerializer s = (XmlSerializer) header_serializers [type];
391                         if (s != null) return;
392
393                         XmlReflectionImporter ri = new XmlReflectionImporter ();
394                         XmlTypeMapping tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
395                         s = new XmlSerializer (tm);
396
397                         header_serializers [type] = s;
398                         header_serializers_byname [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = s;
399                 }
400
401                 internal XmlSerializer GetHeaderSerializer (Type type)
402                 {
403                         return (XmlSerializer) header_serializers [type];
404                 }
405         
406                 internal XmlSerializer GetHeaderSerializer (XmlQualifiedName qname)
407                 {
408                         return (XmlSerializer) header_serializers_byname [qname];
409                 }               
410         }
411 }