First set of attempts to do RPC, but I need to prefix the method name only,
[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 //
7 // (C) 2003 Ximian, Inc.
8 //
9 // TODO:
10 //    
11 //
12
13 using System.Reflection;
14 using System.Collections;
15 using System.Xml.Serialization;
16 using System.Web.Services;
17 using System.Web.Services.Description;
18
19 namespace System.Web.Services.Protocols {
20
21         //
22         // This class represents all the information we extract from a MethodInfo
23         // in the SoapHttpClientProtocol derivative stub class
24         //
25         internal class MethodStubInfo {
26                 internal LogicalMethodInfo MethodInfo;
27
28                 // The name used bythe stub class to reference this method.
29                 internal string Name;
30                 
31                 internal string Action;
32                 internal string Binding;
33
34                 // The name/namespace of the request 
35                 internal string RequestName;
36                 internal string RequestNamespace;
37
38                 // The name/namespace of the response.
39                 internal string ResponseName;
40                 internal string ResponseNamespace;
41                 
42                 internal bool   OneWay;
43                 internal SoapParameterStyle ParameterStyle;
44
45                 internal XmlSerializer RequestSerializer;
46                 internal XmlSerializer ResponseSerializer;
47
48                 //
49                 // Constructor
50                 //
51                 MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source, object kind, XmlReflectionImporter importer)
52                 {
53                         MethodInfo = source;
54
55                         if (kind is SoapDocumentMethodAttribute){
56                                 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
57                                 
58                                 SoapBindingUse use = dma.Use;
59                                 if (use == SoapBindingUse.Default)
60                                         use = parent.Use;
61                                 if (use != SoapBindingUse.Literal)
62                                         throw new Exception ("Only SoapBindingUse.Literal supported");
63                                 
64                                 Action = dma.Action;
65                                 Binding = dma.Binding;
66                                 RequestName = dma.RequestElementName;
67                                 RequestNamespace = dma.RequestNamespace;
68                                 ResponseName = dma.ResponseElementName;
69                                 ResponseNamespace = dma.ResponseNamespace;
70                                 ParameterStyle = dma.ParameterStyle;
71                                 if (ParameterStyle == SoapParameterStyle.Default)
72                                         ParameterStyle = parent.ParameterStyle;
73                                 OneWay = dma.OneWay;
74                         } else {
75                                 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
76
77                                 // Assuem that the TypeStub already caught any possible use of Encoded
78                                 Action = rma.Action;
79                                 Binding = rma.Binding;
80                                 RequestName = rma.RequestElementName;
81                                 RequestNamespace = rma.RequestNamespace;
82                                 ResponseNamespace = rma.ResponseNamespace;
83                                 ResponseName = rma.ResponseElementName;
84                                 OneWay = rma.OneWay;
85                         }
86                         if (Binding == "")
87                                 Binding = parent.BindingName;
88                         if (RequestName == "")
89                                 RequestName = source.Name;
90                         
91                         if (OneWay){
92                                 if (source.ReturnType != typeof (void))
93                                         throw new Exception ("OneWay methods should not have a return value");
94                                 if (source.OutParameters.Length != 0)
95                                         throw new Exception ("OneWay methods should not have out/ref parameters");
96                         }
97                         
98                         object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
99                         if (o.Length == 1){
100                                 WebMethodAttribute wma = (WebMethodAttribute) o [0];
101
102                                 Name = wma.MessageName;
103                                 if (Name == "")
104                                         Name = source.Name;
105                         } else
106                                 Name = source.Name;
107
108                         if (ResponseName == "")
109                                 ResponseName = Name + "Response";
110                         
111                         MakeRequestSerializer (importer);
112                         MakeResponseSerializer (importer);
113                 }
114
115                 static internal MethodStubInfo Create (TypeStubInfo parent, LogicalMethodInfo lmi, XmlReflectionImporter importer)
116                 {
117                         object [] o = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
118                         if (o.Length == 0){
119                                 o = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
120                                 if (o.Length == 0)
121                                         return null;
122                                 return new MethodStubInfo (parent, lmi, o [0], importer);
123                         } else 
124                                 return new MethodStubInfo (parent, lmi, o [0], importer);
125                 }
126
127                 void MakeRequestSerializer (XmlReflectionImporter importer)
128                 {
129                         ParameterInfo [] input = MethodInfo.InParameters;
130                         XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
131                         
132                         for (int i = 0; i < input.Length; i++){
133                                 XmlReflectionMember m = new XmlReflectionMember ();
134                                 m.IsReturnValue = false;
135                                 m.MemberName = input [i].Name;
136                                 m.MemberType = input [i].ParameterType;
137                                 if (m.MemberType.IsByRef)
138                                         m.MemberType = m.MemberType.GetElementType ();
139
140                                 in_members [i] = m;
141                         }
142
143                         XmlMembersMapping [] members = new XmlMembersMapping [1];
144                         try {
145                                 Console.WriteLine ("XmLSerializer: {0} {1}", RequestName, RequestNamespace);
146                                 members [0] = importer.ImportMembersMapping (RequestName, RequestNamespace, in_members, true);
147                                 XmlSerializer [] s = null;
148                                 s = XmlSerializer.FromMappings (members);
149                                 RequestSerializer = s [0];
150                         } catch {
151                                 Console.WriteLine ("Got exception while creating serializer");
152                                 Console.WriteLine ("Method name: " + RequestName + " parameters are:");
153
154                                 for (int i = 0; i < input.Length; i++){
155                                         Console.WriteLine ("    {0}: {1} {2}", i, in_members [i].MemberName, in_members [i].MemberType);
156                                 }
157                                 throw;
158                         }
159                 }
160
161                 void MakeResponseSerializer (XmlReflectionImporter importer)
162                 {
163                         ParameterInfo [] output = MethodInfo.OutParameters;
164                         bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
165                         XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
166                         XmlReflectionMember m;
167                         int idx = 0;
168
169                         if (has_return_value){
170                                 m = new XmlReflectionMember ();
171                                 m.IsReturnValue = true;
172                                 m.MemberName = RequestName + "Result";
173                                 m.MemberType = MethodInfo.ReturnType;
174                                 idx++;
175                                 out_members [0] = m;
176                         }
177                         
178                         for (int i = 0; i < output.Length; i++){
179                                 m = new XmlReflectionMember ();
180                                 m.IsReturnValue = false;
181                                 m.MemberName = output [i].Name;
182                                 m.MemberType = output [i].ParameterType;
183
184                                 if (m.MemberType.IsByRef)
185                                         m.MemberType = m.MemberType.GetElementType ();
186                                 out_members [i + idx] = m;
187                         }
188
189                         try {
190                                 XmlMembersMapping [] members = new XmlMembersMapping [1];
191                                 members [0] = importer.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true);
192                                 XmlSerializer [] s = XmlSerializer.FromMappings (members);
193                                 ResponseSerializer = s [0];
194                         } catch {
195                                 Console.WriteLine ("Got exception while creating serializer");
196                                 Console.WriteLine ("Method name: " + ResponseName + " parameters are:");
197
198                                 for (int i = 0; i < out_members.Length; i++){
199                                         Console.WriteLine ("    {0}: {1} {2}", i, out_members [i].MemberName, out_members [i].MemberType);
200                                 }
201                                 throw;
202                         }
203                 }
204         }
205
206         //
207         // Holds the metadata loaded from the type stub, as well as
208         // the metadata for all the methods in the type
209         //
210         internal class TypeStubInfo {
211                 Hashtable name_to_method = new Hashtable ();
212
213                 // Precomputed
214                 internal SoapParameterStyle      ParameterStyle;
215                 internal SoapServiceRoutingStyle RoutingStyle;
216                 internal SoapBindingUse          Use;
217                 internal string                  WebServiceName;
218                 internal string                  WebServiceNamespace;
219                 internal string                  BindingLocation;
220                 internal string                  BindingName;
221                 internal string                  BindingNamespace;
222
223                 void GetTypeAttributes (Type t)
224                 {
225                         object [] o;
226
227                         o = t.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
228                         if (o.Length != 1)
229                                 throw new Exception ("Expected WebServiceBindingAttribute on "+ t.Name);
230                         WebServiceBindingAttribute b = (WebServiceBindingAttribute) o [0];
231                         BindingLocation = b.Location;
232                         BindingName = b.Name;
233                         BindingNamespace = b.Namespace;
234
235                         o = t.GetCustomAttributes (typeof (WebService), false);
236                         if (o.Length == 1){
237                                 WebServiceAttribute a = (WebServiceAttribute) o [0];
238
239                                 WebServiceName = a.Name;
240                                 WebServiceNamespace = a.Namespace;
241                         } else {
242                                 WebServiceName = t.Name;
243                                 WebServiceNamespace = WebServiceAttribute.DefaultNamespace;
244                         }
245
246                         o = t.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
247                         if (o.Length == 1){
248                                 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
249
250                                 ParameterStyle = a.ParameterStyle;
251                                 RoutingStyle = a.RoutingStyle;
252                                 Use = a.Use;
253                         } else {
254                                 o = t.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
255                                 if (o.Length == 1){
256                                         SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
257                                         
258                                         ParameterStyle = SoapParameterStyle.Wrapped;
259                                         RoutingStyle = srs.RoutingStyle;
260                                         Use = SoapBindingUse.Literal;
261                                 } else {
262                                         ParameterStyle = SoapParameterStyle.Wrapped;
263                                         RoutingStyle = SoapServiceRoutingStyle.SoapAction;
264                                         Use = SoapBindingUse.Literal;
265                                 }
266                         }
267                 }
268
269                 //
270                 // Extract all method information
271                 //
272                 void GetTypeMethods (Type t, XmlReflectionImporter importer)
273                 {
274                         MethodInfo [] type_methods = t.GetMethods (BindingFlags.Instance | BindingFlags.Public);
275                         LogicalMethodInfo [] methods = LogicalMethodInfo.Create (type_methods, LogicalMethodTypes.Sync);
276
277                         foreach (LogicalMethodInfo mi in methods){
278                                 MethodStubInfo msi = MethodStubInfo.Create (this, mi, importer);
279
280                                 if (msi == null)
281                                         continue;
282
283                                 name_to_method [msi.Name] = msi;
284                         }
285                 }
286                 
287                 internal TypeStubInfo (Type t)
288                 {
289                         GetTypeAttributes (t);
290
291                         XmlReflectionImporter importer = new XmlReflectionImporter ();
292                         GetTypeMethods (t, importer);
293                 }
294
295                 internal MethodStubInfo GetMethod (string name)
296                 {
297                         return (MethodStubInfo) name_to_method [name];
298                 }
299         }
300         
301         //
302         // Manages 
303         //
304         internal class TypeStubManager {
305                 static Hashtable type_to_manager;
306                 
307                 static TypeStubManager ()
308                 {
309                         type_to_manager = new Hashtable ();
310                 }
311
312                 //
313                 // This needs to be thread safe
314                 //
315                 static internal TypeStubInfo GetTypeStub (Type t)
316                 {
317                         TypeStubInfo tm = (TypeStubInfo) type_to_manager [t];
318
319                         if (tm != null)
320                                 return tm;
321
322                         lock (typeof (TypeStubInfo)){
323                                 tm = (TypeStubInfo) type_to_manager [t];
324
325                                 if (tm != null)
326                                         return tm;
327                                 
328                                 tm = new TypeStubInfo (t);
329                                 type_to_manager [t] = tm;
330
331                                 return tm;
332                         }
333                 }
334         }
335 }