Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[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                         InputMembersMapping.SetKey(RequestName);
218                         OutputMembersMapping.SetKey(ResponseName);
219
220                         requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
221                         responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
222
223                         object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
224                         ArrayList allHeaderList = new ArrayList (o.Length);
225                         ArrayList inHeaderList = new ArrayList (o.Length);
226                         ArrayList outHeaderList = new ArrayList (o.Length);
227                         ArrayList faultHeaderList = new ArrayList ();
228                         
229                         SoapHeaderDirection unknownHeaderDirections = (SoapHeaderDirection)0;
230                         
231                         for (int i = 0; i < o.Length; i++) {
232                                 SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
233                                 MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
234                                 if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + ".");
235                                 
236                                 HeaderInfo header = new HeaderInfo (mems[0], att);
237                                 allHeaderList.Add (header);
238                                 if (!header.Custom) {
239                                         if ((header.Direction & SoapHeaderDirection.In) != 0)
240                                                 inHeaderList.Add (header);
241                                         if ((header.Direction & SoapHeaderDirection.Out) != 0)
242                                                 outHeaderList.Add (header);
243                                         if ((header.Direction & SoapHeaderDirection.Fault) != 0)
244                                                 faultHeaderList.Add (header);
245                                 } else
246                                         unknownHeaderDirections |= header.Direction;
247                         }
248                         
249                         Headers = (HeaderInfo[]) allHeaderList.ToArray (typeof(HeaderInfo));
250
251                         if (inHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.In) != 0) {
252                                 InHeaders = (HeaderInfo[]) inHeaderList.ToArray (typeof(HeaderInfo));
253                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (InHeaders);
254                                 
255                                 if (Use == SoapBindingUse.Literal)
256                                         InputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
257                                 else
258                                         InputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
259                                 
260                                 InputHeaderMembersMapping.SetKey(RequestName + ":InHeaders");
261                                 
262                                 requestHeadersSerializerId = parent.RegisterSerializer (InputHeaderMembersMapping);
263                         }
264                         
265                         if (outHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Out) != 0) {
266                                 OutHeaders = (HeaderInfo[]) outHeaderList.ToArray (typeof(HeaderInfo));
267                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (OutHeaders);
268                                 
269                                 if (Use == SoapBindingUse.Literal)
270                                         OutputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
271                                 else
272                                         OutputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
273
274                                 OutputHeaderMembersMapping.SetKey(ResponseName + ":OutHeaders");
275
276                                 responseHeadersSerializerId = parent.RegisterSerializer (OutputHeaderMembersMapping);
277                         }
278                         
279                         if (faultHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Fault) != 0) {
280                                 FaultHeaders = (HeaderInfo[]) faultHeaderList.ToArray (typeof(HeaderInfo));
281                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (FaultHeaders);
282                                 
283                                 if (Use == SoapBindingUse.Literal)
284                                         FaultHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
285                                 else
286                                         FaultHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
287                                 
288                                 faultHeadersSerializerId = parent.RegisterSerializer (FaultHeaderMembersMapping);
289                         }
290                         
291                         SoapExtensions = SoapExtension.GetMethodExtensions (source);
292                 }
293
294                 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
295                 {
296                         ParameterInfo [] input = MethodInfo.InParameters;
297                         XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
298
299                         for (int i = 0; i < input.Length; i++)
300                         {
301                                 XmlReflectionMember m = new XmlReflectionMember ();
302                                 m.IsReturnValue = false;
303                                 m.MemberName = input [i].Name;
304                                 m.MemberType = input [i].ParameterType;
305
306                                 m.XmlAttributes = new XmlAttributes (input[i]);
307                                 m.SoapAttributes = new SoapAttributes (input[i]);
308
309                                 if (m.MemberType.IsByRef)
310                                         m.MemberType = m.MemberType.GetElementType ();
311                                 if (optional_ns != null)
312                                         m.XmlAttributes.XmlElements.Add (optional_ns);
313                                 in_members [i] = m;
314                         }
315                         return in_members;
316                 }
317                 
318                 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
319                 {
320                         ParameterInfo [] output = MethodInfo.OutParameters;
321                         bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
322                         XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
323                         XmlReflectionMember m;
324                         int idx = 0;
325
326                         if (has_return_value)
327                         {
328                                 m = new XmlReflectionMember ();
329                                 m.IsReturnValue = true;
330                                 m.MemberName = Name + "Result";
331                                 m.MemberType = MethodInfo.ReturnType;
332
333                                 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
334                                 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
335
336                                 if (optional_ns != null)
337                                         m.XmlAttributes.XmlElements.Add (optional_ns);
338                                 idx++;
339                                 out_members [0] = m;
340                         }
341                         
342                         for (int i = 0; i < output.Length; i++)
343                         {
344                                 m = new XmlReflectionMember ();
345                                 m.IsReturnValue = false;
346                                 m.MemberName = output [i].Name;
347                                 m.MemberType = output [i].ParameterType;
348                                 m.XmlAttributes = new XmlAttributes (output[i]);
349                                 m.SoapAttributes = new SoapAttributes (output[i]);
350
351                                 if (m.MemberType.IsByRef)
352                                         m.MemberType = m.MemberType.GetElementType ();
353                                 if (optional_ns != null)
354                                         m.XmlAttributes.XmlElements.Add (optional_ns);
355                                 out_members [i + idx] = m;
356                         }
357                         return out_members;
358                 }
359
360                 XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers)
361                 {
362                         XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length];
363
364                         for (int n=0; n<headers.Length; n++)
365                         {
366                                 HeaderInfo header = headers [n];
367                                 
368                                 XmlReflectionMember m = new XmlReflectionMember ();
369                                 m.IsReturnValue = false;
370                                 m.MemberName = header.HeaderType.Name;
371                                 m.MemberType = header.HeaderType;
372
373                                 // MS.NET reflects header classes in a weird way. The root element
374                                 // name is the CLR class name unless it is specified in an XmlRootAttribute.
375                                 // The usual is to use the xml type name by default, but not in this case.
376                                 
377                                 XmlAttributes ats = new XmlAttributes (header.HeaderType);
378                                 if (ats.XmlRoot != null) {
379                                         XmlElementAttribute xe = new XmlElementAttribute ();
380                                         xe.ElementName = ats.XmlRoot.ElementName;
381                                         xe.Namespace = ats.XmlRoot.Namespace;
382                                         m.XmlAttributes = new XmlAttributes ();
383                                         m.XmlAttributes.XmlElements.Add (xe);
384                                 }
385                                 
386                                 mems [n] = m;
387                         }
388                         return mems;
389                 }
390
391                 public HeaderInfo GetHeaderInfo (Type headerType)
392                 {
393                         foreach (HeaderInfo headerInfo in Headers)
394                                 if (headerInfo.HeaderType == headerType) return headerInfo;
395                         return null;
396                 }
397                 
398                 public XmlSerializer GetBodySerializer (SoapHeaderDirection dir, bool soap12)
399                 {
400                         switch (dir) {
401                                 case SoapHeaderDirection.In: return RequestSerializer;
402                                 case SoapHeaderDirection.Out: return ResponseSerializer;
403                                 case SoapHeaderDirection.Fault: return soap12 ? Soap12Fault.Serializer : Fault.Serializer;
404                                 default: return null;
405                         }
406                 }
407                 
408                 public XmlSerializer GetHeaderSerializer (SoapHeaderDirection dir)
409                 {
410                         switch (dir) {
411                                 case SoapHeaderDirection.In: return RequestHeadersSerializer;
412                                 case SoapHeaderDirection.Out: return ResponseHeadersSerializer;
413                                 case SoapHeaderDirection.Fault: return FaultHeadersSerializer;
414                                 default: return null;
415                         }
416                 }
417                 
418                 HeaderInfo[] GetHeaders (SoapHeaderDirection dir)
419                 {
420                         switch (dir) {
421                                 case SoapHeaderDirection.In: return InHeaders;
422                                 case SoapHeaderDirection.Out: return OutHeaders;
423                                 case SoapHeaderDirection.Fault: return FaultHeaders;
424                                 default: return null;
425                         }
426                 }
427                 
428                 public object[] GetHeaderValueArray (SoapHeaderDirection dir, SoapHeaderCollection headers)
429                 {
430                         HeaderInfo[] headerInfos = GetHeaders (dir);
431                         if (headerInfos == null) return null;
432
433                         object[] hs = new object [headerInfos.Length];
434                         
435                         for (int n=0; n<headers.Count; n++) {
436                                 SoapHeader h = headers[n];
437                                 Type t = h.GetType();
438                                 for (int i=0; i<headerInfos.Length; i++)
439                                         if (headerInfos [i].HeaderType == t)
440                                                 hs [i] = h;
441                         }
442                         return hs;
443                 }
444         }
445
446         //
447         // Holds the metadata loaded from the type stub, as well as
448         // the metadata for all the methods in the type
449         //
450         internal class SoapTypeStubInfo : TypeStubInfo
451         {
452                 Hashtable methods_byaction = new Hashtable (); 
453
454                 // Precomputed
455                 internal SoapParameterStyle      ParameterStyle;
456                 internal SoapExtensionRuntimeConfig[][] SoapExtensions;
457                 internal SoapBindingStyle SoapBindingStyle;
458                 internal XmlReflectionImporter  xmlImporter;
459                 internal SoapReflectionImporter soapImporter;
460
461                 public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
462                 : base (logicalTypeInfo)
463                 {
464                         xmlImporter = new XmlReflectionImporter ();
465                         soapImporter = new SoapReflectionImporter ();
466                                 
467                         if (typeof (SoapHttpClientProtocol).IsAssignableFrom (Type))
468                         {
469                                 if (Bindings.Count == 0 || ((BindingInfo)Bindings[0]).WebServiceBindingAttribute == null)
470                                         throw new InvalidOperationException ("WebServiceBindingAttribute is required on proxy class '" + Type + "'.");
471                                 if (Bindings.Count > 1)
472                                         throw new InvalidOperationException ("Only one WebServiceBinding attribute may be specified on type '" + Type + "'.");
473                         }
474
475                         object [] o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
476                         if (o.Length == 1){
477                                 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
478
479                                 ParameterStyle = a.ParameterStyle;
480                                 SoapBindingStyle = SoapBindingStyle.Document;
481                         } else {
482                                 o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
483                                 if (o.Length == 1){
484                                         ParameterStyle = SoapParameterStyle.Wrapped;
485                                         SoapBindingStyle = SoapBindingStyle.Rpc;
486                                 } else {
487                                         ParameterStyle = SoapParameterStyle.Wrapped;
488                                         SoapBindingStyle = SoapBindingStyle.Document;
489                                 }
490                         }
491                         
492                         if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
493                         
494                         xmlImporter.IncludeTypes (Type);
495                         soapImporter.IncludeTypes (Type);
496
497 #if MOBILE || XAMMAC_4_5
498                         SoapExtensions = new SoapExtensionRuntimeConfig [2][];
499 #else
500                         SoapExtensions = SoapExtension.GetTypeExtensions (Type);
501 #endif
502                 }
503
504                 internal SoapServiceRoutingStyle RoutingStyle {
505                         get { return LogicalType.RoutingStyle; }
506                 }
507
508                 public override XmlReflectionImporter XmlImporter 
509                 {
510                         get { return xmlImporter; }
511                 }
512
513                 public override SoapReflectionImporter SoapImporter 
514                 {
515                         get { return soapImporter; }
516                 }
517                 
518                 public override string ProtocolName
519                 {
520                         get { return "Soap"; }
521                 }
522                 
523                 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
524                 {
525                         SoapMethodStubInfo res = null;
526                         object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
527                         if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
528
529                         if (ats.Length == 0 && isClientProxy)
530                                 return null;
531                         else if (ats.Length == 0)
532                                 res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
533                         else
534                                 res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
535                                 
536                         methods_byaction [res.Action] = res;
537                         return res;
538                 }
539                 
540                 public SoapMethodStubInfo GetMethodForSoapAction (string name)
541                 {
542                         return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];
543                 }
544         }
545
546         internal class Soap12TypeStubInfo : SoapTypeStubInfo
547         {
548                 public Soap12TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
549                 : base (logicalTypeInfo)
550                 {
551                 }
552
553                 public override string ProtocolName
554                 {
555                         get { return "Soap12"; }
556                 }
557         }
558 }