Merge branch 'master' of github.com:mono/mono
[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
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using HeaderInfo = System.Web.Services.Protocols.SoapHeaderMapping;
33
34 using System.Reflection;
35 using System.Collections;
36 using System.Xml;
37 using System.Xml.Serialization;
38 using System.Web.Services;
39 using System.Web.Services.Description;
40
41 namespace System.Web.Services.Protocols {
42
43         //
44         // This class represents all the information we extract from a MethodInfo
45         // in the SoapHttpClientProtocol derivative stub class
46         //
47         internal class SoapMethodStubInfo : MethodStubInfo
48         {
49                 internal readonly string Action;
50                 internal readonly string Binding;
51
52                 // The name/namespace of the request 
53                 internal readonly string RequestName;
54                 internal readonly string RequestNamespace;
55
56                 // The name/namespace of the response.
57                 internal readonly string ResponseName;
58                 internal readonly string ResponseNamespace;
59
60                 internal readonly bool OneWay;
61                 internal readonly SoapParameterStyle ParameterStyle;
62                 internal readonly SoapBindingStyle SoapBindingStyle;
63                 internal readonly SoapBindingUse Use;
64
65                 internal readonly HeaderInfo [] Headers;
66                 internal readonly HeaderInfo [] InHeaders;
67                 internal readonly HeaderInfo [] OutHeaders;
68                 internal readonly HeaderInfo [] FaultHeaders;
69                 internal readonly SoapExtensionRuntimeConfig [] SoapExtensions;
70
71                 internal readonly XmlMembersMapping InputMembersMapping;
72                 internal readonly XmlMembersMapping OutputMembersMapping;
73                 internal readonly XmlMembersMapping InputHeaderMembersMapping;
74                 internal readonly XmlMembersMapping OutputHeaderMembersMapping;
75                 internal readonly XmlMembersMapping FaultHeaderMembersMapping;
76
77                 private readonly int requestSerializerId;
78                 private readonly int responseSerializerId;
79                 private readonly int requestHeadersSerializerId = -1;
80                 private readonly int responseHeadersSerializerId = -1;
81                 private readonly int faultHeadersSerializerId = -1;
82                 
83                 internal XmlSerializer RequestSerializer
84                 {
85                         get { return TypeStub.GetSerializer (requestSerializerId); }
86                 }
87                 
88                 internal XmlSerializer ResponseSerializer
89                 {
90                         get { return TypeStub.GetSerializer (responseSerializerId); }
91                 }
92                 
93                 internal XmlSerializer RequestHeadersSerializer
94                 {
95                         get { return requestHeadersSerializerId != -1 ? TypeStub.GetSerializer (requestHeadersSerializerId) : null; }
96                 }
97                 
98                 internal XmlSerializer ResponseHeadersSerializer
99                 {
100                         get { return responseHeadersSerializerId != -1 ? TypeStub.GetSerializer (responseHeadersSerializerId) : null; }
101                 }
102                 
103                 internal XmlSerializer FaultHeadersSerializer
104                 {
105                         get { return faultHeadersSerializerId != -1 ? TypeStub.GetSerializer (faultHeadersSerializerId) : null; }
106                 }
107                 
108
109                 //
110                 // Constructor
111                 //
112                 public SoapMethodStubInfo (TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
113                 : base (typeStub, source)
114                 {
115                         SoapTypeStubInfo parent = (SoapTypeStubInfo) typeStub;
116                         XmlElementAttribute optional_ns = null;
117
118                         if (kind == null) {
119                                 Use = parent.LogicalType.BindingUse;
120                                 RequestName = "";
121                                 RequestNamespace = "";
122                                 ResponseName = "";
123                                 ResponseNamespace = "";
124                                 ParameterStyle = parent.ParameterStyle;
125                                 SoapBindingStyle = parent.SoapBindingStyle;
126                                 OneWay = false;
127 // disabled (see bug #332150)
128 //#if NET_2_0
129 //                              if (parent.Type != source.DeclaringType)
130 //                                      Binding = source.DeclaringType.Name + parent.ProtocolName;
131 //#endif
132                         }
133                         else if (kind is SoapDocumentMethodAttribute){
134                                 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
135                                 
136                                 Use = dma.Use;
137                                 if (Use == SoapBindingUse.Default) {
138                                         if (parent.SoapBindingStyle == SoapBindingStyle.Document)
139                                                 Use = parent.LogicalType.BindingUse;
140                                         else
141                                                 Use = SoapBindingUse.Literal;
142                                 }
143                                 
144                                 Action = dma.Action;
145                                 Binding = dma.Binding;
146                                 RequestName = dma.RequestElementName;
147                                 RequestNamespace = dma.RequestNamespace;
148                                 ResponseName = dma.ResponseElementName;
149                                 ResponseNamespace = dma.ResponseNamespace;
150                                 ParameterStyle = dma.ParameterStyle;
151                                 if (ParameterStyle == SoapParameterStyle.Default)
152                                         ParameterStyle = parent.ParameterStyle;
153                                 OneWay = dma.OneWay;
154                                 SoapBindingStyle = SoapBindingStyle.Document;
155                         } else {
156                                 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
157                                 Use = SoapBindingUse.Encoded;   // RPC always use encoded
158
159                                 Action = rma.Action;
160                                 if (Action != null && Action.Length == 0)
161                                         Action = null;
162                                 Binding = rma.Binding;
163                                 
164                                 // When using RPC, MS.NET seems to ignore RequestElementName and
165                                 // MessageName, and it always uses the method name
166                                 RequestName = source.Name;
167                                 ResponseName = source.Name + "Response";
168 //                              RequestName = rma.RequestElementName;
169 //                              ResponseName = rma.ResponseElementName;
170                                 RequestNamespace = rma.RequestNamespace;
171                                 ResponseNamespace = rma.ResponseNamespace;
172                                 ParameterStyle = SoapParameterStyle.Wrapped;
173                                 OneWay = rma.OneWay;
174                                 SoapBindingStyle = SoapBindingStyle.Rpc;
175
176                                 // For RPC calls, make all arguments be part of the empty namespace
177                                 optional_ns = new XmlElementAttribute ();
178                                 optional_ns.Namespace = "";
179                         }
180
181                         if (OneWay){
182                                 if (source.ReturnType != typeof (void))
183                                         throw new Exception ("OneWay methods should not have a return value.");
184                                 if (source.OutParameters.Length != 0)
185                                         throw new Exception ("OneWay methods should not have out/ref parameters.");
186                         }
187                         
188                         BindingInfo binfo = parent.GetBinding (Binding);
189                         if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'.");
190                         
191                         string serviceNamespace = binfo.Namespace;
192                                 
193                         if (RequestNamespace == "") RequestNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use);
194                         if (ResponseNamespace == "") ResponseNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use);
195                         if (RequestName == "") RequestName = Name;
196                         if (ResponseName == "") ResponseName = Name + "Response";
197                         if (Action == null)
198                                 Action = serviceNamespace.EndsWith("/") ? (serviceNamespace + Name) : (serviceNamespace + "/" + Name);
199                         
200                         bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
201                         bool writeAccessors = (SoapBindingStyle == SoapBindingStyle.Rpc);
202                         
203                         XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
204                         XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
205
206                         if (Use == SoapBindingUse.Literal) {
207                                 xmlImporter.IncludeTypes (source.CustomAttributeProvider);
208                                 InputMembersMapping = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem);
209                                 OutputMembersMapping = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem);
210                         }
211                         else {
212                                 soapImporter.IncludeTypes (source.CustomAttributeProvider);
213                                 InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, writeAccessors);
214                                 OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, writeAccessors);
215                         }
216
217                         requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
218                         responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
219
220                         object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
221                         ArrayList allHeaderList = new ArrayList (o.Length);
222                         ArrayList inHeaderList = new ArrayList (o.Length);
223                         ArrayList outHeaderList = new ArrayList (o.Length);
224                         ArrayList faultHeaderList = new ArrayList ();
225                         
226                         SoapHeaderDirection unknownHeaderDirections = (SoapHeaderDirection)0;
227                         
228                         for (int i = 0; i < o.Length; i++) {
229                                 SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
230                                 MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
231                                 if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + ".");
232                                 
233                                 HeaderInfo header = new HeaderInfo (mems[0], att);
234                                 allHeaderList.Add (header);
235                                 if (!header.Custom) {
236                                         if ((header.Direction & SoapHeaderDirection.In) != 0)
237                                                 inHeaderList.Add (header);
238                                         if ((header.Direction & SoapHeaderDirection.Out) != 0)
239                                                 outHeaderList.Add (header);
240                                         if ((header.Direction & SoapHeaderDirection.Fault) != 0)
241                                                 faultHeaderList.Add (header);
242                                 } else
243                                         unknownHeaderDirections |= header.Direction;
244                         }
245                         
246                         Headers = (HeaderInfo[]) allHeaderList.ToArray (typeof(HeaderInfo));
247
248                         if (inHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.In) != 0) {
249                                 InHeaders = (HeaderInfo[]) inHeaderList.ToArray (typeof(HeaderInfo));
250                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (InHeaders);
251                                 
252                                 if (Use == SoapBindingUse.Literal)
253                                         InputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
254                                 else
255                                         InputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
256                                 
257                                 requestHeadersSerializerId = parent.RegisterSerializer (InputHeaderMembersMapping);
258                         }
259                         
260                         if (outHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Out) != 0) {
261                                 OutHeaders = (HeaderInfo[]) outHeaderList.ToArray (typeof(HeaderInfo));
262                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (OutHeaders);
263                                 
264                                 if (Use == SoapBindingUse.Literal)
265                                         OutputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
266                                 else
267                                         OutputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
268                                 
269                                 responseHeadersSerializerId = parent.RegisterSerializer (OutputHeaderMembersMapping);
270                         }
271                         
272                         if (faultHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Fault) != 0) {
273                                 FaultHeaders = (HeaderInfo[]) faultHeaderList.ToArray (typeof(HeaderInfo));
274                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (FaultHeaders);
275                                 
276                                 if (Use == SoapBindingUse.Literal)
277                                         FaultHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
278                                 else
279                                         FaultHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
280                                 
281                                 faultHeadersSerializerId = parent.RegisterSerializer (FaultHeaderMembersMapping);
282                         }
283                         
284                         SoapExtensions = SoapExtension.GetMethodExtensions (source);
285                 }
286
287                 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
288                 {
289                         ParameterInfo [] input = MethodInfo.InParameters;
290                         XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
291
292                         for (int i = 0; i < input.Length; i++)
293                         {
294                                 XmlReflectionMember m = new XmlReflectionMember ();
295                                 m.IsReturnValue = false;
296                                 m.MemberName = input [i].Name;
297                                 m.MemberType = input [i].ParameterType;
298
299                                 m.XmlAttributes = new XmlAttributes (input[i]);
300                                 m.SoapAttributes = new SoapAttributes (input[i]);
301
302                                 if (m.MemberType.IsByRef)
303                                         m.MemberType = m.MemberType.GetElementType ();
304                                 if (optional_ns != null)
305                                         m.XmlAttributes.XmlElements.Add (optional_ns);
306                                 in_members [i] = m;
307                         }
308                         return in_members;
309                 }
310                 
311                 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
312                 {
313                         ParameterInfo [] output = MethodInfo.OutParameters;
314                         bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
315                         XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
316                         XmlReflectionMember m;
317                         int idx = 0;
318
319                         if (has_return_value)
320                         {
321                                 m = new XmlReflectionMember ();
322                                 m.IsReturnValue = true;
323                                 m.MemberName = Name + "Result";
324                                 m.MemberType = MethodInfo.ReturnType;
325
326                                 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
327                                 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
328
329                                 if (optional_ns != null)
330                                         m.XmlAttributes.XmlElements.Add (optional_ns);
331                                 idx++;
332                                 out_members [0] = m;
333                         }
334                         
335                         for (int i = 0; i < output.Length; i++)
336                         {
337                                 m = new XmlReflectionMember ();
338                                 m.IsReturnValue = false;
339                                 m.MemberName = output [i].Name;
340                                 m.MemberType = output [i].ParameterType;
341                                 m.XmlAttributes = new XmlAttributes (output[i]);
342                                 m.SoapAttributes = new SoapAttributes (output[i]);
343
344                                 if (m.MemberType.IsByRef)
345                                         m.MemberType = m.MemberType.GetElementType ();
346                                 if (optional_ns != null)
347                                         m.XmlAttributes.XmlElements.Add (optional_ns);
348                                 out_members [i + idx] = m;
349                         }
350                         return out_members;
351                 }
352
353                 XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers)
354                 {
355                         XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length];
356
357                         for (int n=0; n<headers.Length; n++)
358                         {
359                                 HeaderInfo header = headers [n];
360                                 
361                                 XmlReflectionMember m = new XmlReflectionMember ();
362                                 m.IsReturnValue = false;
363                                 m.MemberName = header.HeaderType.Name;
364                                 m.MemberType = header.HeaderType;
365
366                                 // MS.NET reflects header classes in a weird way. The root element
367                                 // name is the CLR class name unless it is specified in an XmlRootAttribute.
368                                 // The usual is to use the xml type name by default, but not in this case.
369                                 
370                                 XmlAttributes ats = new XmlAttributes (header.HeaderType);
371                                 if (ats.XmlRoot != null) {
372                                         XmlElementAttribute xe = new XmlElementAttribute ();
373                                         xe.ElementName = ats.XmlRoot.ElementName;
374                                         xe.Namespace = ats.XmlRoot.Namespace;
375                                         m.XmlAttributes = new XmlAttributes ();
376                                         m.XmlAttributes.XmlElements.Add (xe);
377                                 }
378                                 
379                                 mems [n] = m;
380                         }
381                         return mems;
382                 }
383
384                 public HeaderInfo GetHeaderInfo (Type headerType)
385                 {
386                         foreach (HeaderInfo headerInfo in Headers)
387                                 if (headerInfo.HeaderType == headerType) return headerInfo;
388                         return null;
389                 }
390                 
391                 public XmlSerializer GetBodySerializer (SoapHeaderDirection dir, bool soap12)
392                 {
393                         switch (dir) {
394                                 case SoapHeaderDirection.In: return RequestSerializer;
395                                 case SoapHeaderDirection.Out: return ResponseSerializer;
396                                 case SoapHeaderDirection.Fault: return soap12 ? Soap12Fault.Serializer : Fault.Serializer;
397                                 default: return null;
398                         }
399                 }
400                 
401                 public XmlSerializer GetHeaderSerializer (SoapHeaderDirection dir)
402                 {
403                         switch (dir) {
404                                 case SoapHeaderDirection.In: return RequestHeadersSerializer;
405                                 case SoapHeaderDirection.Out: return ResponseHeadersSerializer;
406                                 case SoapHeaderDirection.Fault: return FaultHeadersSerializer;
407                                 default: return null;
408                         }
409                 }
410                 
411                 HeaderInfo[] GetHeaders (SoapHeaderDirection dir)
412                 {
413                         switch (dir) {
414                                 case SoapHeaderDirection.In: return InHeaders;
415                                 case SoapHeaderDirection.Out: return OutHeaders;
416                                 case SoapHeaderDirection.Fault: return FaultHeaders;
417                                 default: return null;
418                         }
419                 }
420                 
421                 public object[] GetHeaderValueArray (SoapHeaderDirection dir, SoapHeaderCollection headers)
422                 {
423                         HeaderInfo[] headerInfos = GetHeaders (dir);
424                         if (headerInfos == null) return null;
425
426                         object[] hs = new object [headerInfos.Length];
427                         
428                         for (int n=0; n<headers.Count; n++) {
429                                 SoapHeader h = headers[n];
430                                 Type t = h.GetType();
431                                 for (int i=0; i<headerInfos.Length; i++)
432                                         if (headerInfos [i].HeaderType == t)
433                                                 hs [i] = h;
434                         }
435                         return hs;
436                 }
437         }
438
439         //
440         // Holds the metadata loaded from the type stub, as well as
441         // the metadata for all the methods in the type
442         //
443         internal class SoapTypeStubInfo : TypeStubInfo
444         {
445                 Hashtable[] header_serializers = new Hashtable [3];
446                 Hashtable[] header_serializers_byname = new Hashtable [3];
447                 Hashtable methods_byaction = new Hashtable (); 
448
449                 // Precomputed
450                 internal SoapParameterStyle      ParameterStyle;
451                 internal SoapExtensionRuntimeConfig[][] SoapExtensions;
452                 internal SoapBindingStyle SoapBindingStyle;
453                 internal XmlReflectionImporter  xmlImporter;
454                 internal SoapReflectionImporter soapImporter;
455
456                 public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
457                 : base (logicalTypeInfo)
458                 {
459                         xmlImporter = new XmlReflectionImporter ();
460                         soapImporter = new SoapReflectionImporter ();
461                                 
462                         if (typeof (SoapHttpClientProtocol).IsAssignableFrom (Type))
463                         {
464                                 if (Bindings.Count == 0 || ((BindingInfo)Bindings[0]).WebServiceBindingAttribute == null)
465                                         throw new InvalidOperationException ("WebServiceBindingAttribute is required on proxy class '" + Type + "'.");
466                                 if (Bindings.Count > 1)
467                                         throw new InvalidOperationException ("Only one WebServiceBinding attribute may be specified on type '" + Type + "'.");
468                         }
469
470                         object [] o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
471                         if (o.Length == 1){
472                                 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
473
474                                 ParameterStyle = a.ParameterStyle;
475                                 SoapBindingStyle = SoapBindingStyle.Document;
476                         } else {
477                                 o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
478                                 if (o.Length == 1){
479                                         SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
480                                         
481                                         ParameterStyle = SoapParameterStyle.Wrapped;
482                                         SoapBindingStyle = SoapBindingStyle.Rpc;
483                                 } else {
484                                         ParameterStyle = SoapParameterStyle.Wrapped;
485                                         SoapBindingStyle = SoapBindingStyle.Document;
486                                 }
487                         }
488                         
489                         if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
490                         
491                         xmlImporter.IncludeTypes (Type);
492                         soapImporter.IncludeTypes (Type);
493
494 #if MOBILE
495                         SoapExtensions = new SoapExtensionRuntimeConfig [2][];
496 #else
497                         SoapExtensions = SoapExtension.GetTypeExtensions (Type);
498 #endif
499                 }
500
501                 internal SoapServiceRoutingStyle RoutingStyle {
502                         get { return LogicalType.RoutingStyle; }
503                 }
504
505                 public override XmlReflectionImporter XmlImporter 
506                 {
507                         get { return xmlImporter; }
508                 }
509
510                 public override SoapReflectionImporter SoapImporter 
511                 {
512                         get { return soapImporter; }
513                 }
514                 
515                 public override string ProtocolName
516                 {
517                         get { return "Soap"; }
518                 }
519                 
520                 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
521                 {
522                         SoapMethodStubInfo res = null;
523                         object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
524                         if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
525
526                         if (ats.Length == 0 && isClientProxy)
527                                 return null;
528                         else if (ats.Length == 0)
529                                 res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
530                         else
531                                 res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
532                                 
533                         methods_byaction [res.Action] = res;
534                         return res;
535                 }
536                 
537                 public SoapMethodStubInfo GetMethodForSoapAction (string name)
538                 {
539                         return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];
540                 }
541         }
542
543         internal class Soap12TypeStubInfo : SoapTypeStubInfo
544         {
545                 public Soap12TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
546                 : base (logicalTypeInfo)
547                 {
548                 }
549
550                 public override string ProtocolName
551                 {
552                         get { return "Soap12"; }
553                 }
554         }
555 }