2007-05-08 Atsushi Enomoto <atsushi@ximian.com>
[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 #if NET_2_0
128                                 if (parent.Type != source.DeclaringType)
129                                         Binding = source.DeclaringType.Name + parent.ProtocolName;
130 #endif
131                         }
132                         else if (kind is SoapDocumentMethodAttribute){
133                                 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
134                                 
135                                 Use = dma.Use;
136                                 if (Use == SoapBindingUse.Default) {
137                                         if (parent.SoapBindingStyle == SoapBindingStyle.Document)
138                                                 Use = parent.LogicalType.BindingUse;
139                                         else
140                                                 Use = SoapBindingUse.Literal;
141                                 }
142                                 
143                                 Action = dma.Action;
144                                 Binding = dma.Binding;
145                                 RequestName = dma.RequestElementName;
146                                 RequestNamespace = dma.RequestNamespace;
147                                 ResponseName = dma.ResponseElementName;
148                                 ResponseNamespace = dma.ResponseNamespace;
149                                 ParameterStyle = dma.ParameterStyle;
150                                 if (ParameterStyle == SoapParameterStyle.Default)
151                                         ParameterStyle = parent.ParameterStyle;
152                                 OneWay = dma.OneWay;
153                                 SoapBindingStyle = SoapBindingStyle.Document;
154                         } else {
155                                 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
156                                 Use = SoapBindingUse.Encoded;   // RPC always use encoded
157
158                                 Action = rma.Action;
159                                 Binding = rma.Binding;
160                                 
161                                 // When using RPC, MS.NET seems to ignore RequestElementName and
162                                 // MessageName, and it always uses the method name
163                                 RequestName = source.Name;
164                                 ResponseName = source.Name + "Response";
165 //                              RequestName = rma.RequestElementName;
166 //                              ResponseName = rma.ResponseElementName;
167                                 RequestNamespace = rma.RequestNamespace;
168                                 ResponseNamespace = rma.ResponseNamespace;
169                                 ParameterStyle = SoapParameterStyle.Wrapped;
170                                 OneWay = rma.OneWay;
171                                 SoapBindingStyle = SoapBindingStyle.Rpc;
172
173                                 // For RPC calls, make all arguments be part of the empty namespace
174                                 optional_ns = new XmlElementAttribute ();
175                                 optional_ns.Namespace = "";
176                         }
177
178                         if (OneWay){
179                                 if (source.ReturnType != typeof (void))
180                                         throw new Exception ("OneWay methods should not have a return value.");
181                                 if (source.OutParameters.Length != 0)
182                                         throw new Exception ("OneWay methods should not have out/ref parameters.");
183                         }
184                         
185                         BindingInfo binfo = parent.GetBinding (Binding);
186                         if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'.");
187                         
188                         string serviceNamespace = binfo.Namespace;
189                                 
190                         if (RequestNamespace == "") RequestNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use);
191                         if (ResponseNamespace == "") ResponseNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use);
192                         if (RequestName == "") RequestName = Name;
193                         if (ResponseName == "") ResponseName = Name + "Response";
194                         if (Action == null || Action == "")
195                                 Action = serviceNamespace.EndsWith("/") ? (serviceNamespace + Name) : (serviceNamespace + "/" + Name);
196                         
197                         bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
198                         bool writeAccessors = (SoapBindingStyle == SoapBindingStyle.Rpc);
199                         
200                         XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
201                         XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
202
203                         if (Use == SoapBindingUse.Literal) {
204                                 xmlImporter.IncludeTypes (source.CustomAttributeProvider);
205                                 InputMembersMapping = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem);
206                                 OutputMembersMapping = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem);
207                         }
208                         else {
209                                 soapImporter.IncludeTypes (source.CustomAttributeProvider);
210                                 InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, writeAccessors);
211                                 OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, writeAccessors);
212                         }
213
214                         requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
215                         responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
216
217                         object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
218                         ArrayList allHeaderList = new ArrayList (o.Length);
219                         ArrayList inHeaderList = new ArrayList (o.Length);
220                         ArrayList outHeaderList = new ArrayList (o.Length);
221                         ArrayList faultHeaderList = new ArrayList ();
222                         
223                         SoapHeaderDirection unknownHeaderDirections = (SoapHeaderDirection)0;
224                         
225                         for (int i = 0; i < o.Length; i++) {
226                                 SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
227                                 MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
228                                 if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + ".");
229                                 
230                                 HeaderInfo header = new HeaderInfo (mems[0], att);
231                                 allHeaderList.Add (header);
232                                 if (!header.Custom) {
233                                         if ((header.Direction & SoapHeaderDirection.In) != 0)
234                                                 inHeaderList.Add (header);
235                                         if ((header.Direction & SoapHeaderDirection.Out) != 0)
236                                                 outHeaderList.Add (header);
237                                         if ((header.Direction & SoapHeaderDirection.Fault) != 0)
238                                                 faultHeaderList.Add (header);
239                                 } else
240                                         unknownHeaderDirections |= header.Direction;
241                         }
242                         
243                         Headers = (HeaderInfo[]) allHeaderList.ToArray (typeof(HeaderInfo));
244
245                         if (inHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.In) != 0) {
246                                 InHeaders = (HeaderInfo[]) inHeaderList.ToArray (typeof(HeaderInfo));
247                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (InHeaders);
248                                 
249                                 if (Use == SoapBindingUse.Literal)
250                                         InputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
251                                 else
252                                         InputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
253                                 
254                                 requestHeadersSerializerId = parent.RegisterSerializer (InputHeaderMembersMapping);
255                         }
256                         
257                         if (outHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Out) != 0) {
258                                 OutHeaders = (HeaderInfo[]) outHeaderList.ToArray (typeof(HeaderInfo));
259                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (OutHeaders);
260                                 
261                                 if (Use == SoapBindingUse.Literal)
262                                         OutputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
263                                 else
264                                         OutputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
265                                 
266                                 responseHeadersSerializerId = parent.RegisterSerializer (OutputHeaderMembersMapping);
267                         }
268                         
269                         if (faultHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Fault) != 0) {
270                                 FaultHeaders = (HeaderInfo[]) faultHeaderList.ToArray (typeof(HeaderInfo));
271                                 XmlReflectionMember[] members = BuildHeadersReflectionMembers (FaultHeaders);
272                                 
273                                 if (Use == SoapBindingUse.Literal)
274                                         FaultHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
275                                 else
276                                         FaultHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
277                                 
278                                 faultHeadersSerializerId = parent.RegisterSerializer (FaultHeaderMembersMapping);
279                         }
280                         
281                         SoapExtensions = SoapExtension.GetMethodExtensions (source);
282                 }
283
284                 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
285                 {
286                         ParameterInfo [] input = MethodInfo.InParameters;
287                         XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
288
289                         for (int i = 0; i < input.Length; i++)
290                         {
291                                 XmlReflectionMember m = new XmlReflectionMember ();
292                                 m.IsReturnValue = false;
293                                 m.MemberName = input [i].Name;
294                                 m.MemberType = input [i].ParameterType;
295
296                                 m.XmlAttributes = new XmlAttributes (input[i]);
297                                 m.SoapAttributes = new SoapAttributes (input[i]);
298
299                                 if (m.MemberType.IsByRef)
300                                         m.MemberType = m.MemberType.GetElementType ();
301                                 if (optional_ns != null)
302                                         m.XmlAttributes.XmlElements.Add (optional_ns);
303                                 in_members [i] = m;
304                         }
305                         return in_members;
306                 }
307                 
308                 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
309                 {
310                         ParameterInfo [] output = MethodInfo.OutParameters;
311                         bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
312                         XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
313                         XmlReflectionMember m;
314                         int idx = 0;
315
316                         if (has_return_value)
317                         {
318                                 m = new XmlReflectionMember ();
319                                 m.IsReturnValue = true;
320                                 m.MemberName = RequestName + "Result";
321                                 m.MemberType = MethodInfo.ReturnType;
322
323                                 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
324                                 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
325
326                                 if (optional_ns != null)
327                                         m.XmlAttributes.XmlElements.Add (optional_ns);
328                                 idx++;
329                                 out_members [0] = m;
330                         }
331                         
332                         for (int i = 0; i < output.Length; i++)
333                         {
334                                 m = new XmlReflectionMember ();
335                                 m.IsReturnValue = false;
336                                 m.MemberName = output [i].Name;
337                                 m.MemberType = output [i].ParameterType;
338                                 m.XmlAttributes = new XmlAttributes (output[i]);
339                                 m.SoapAttributes = new SoapAttributes (output[i]);
340
341                                 if (m.MemberType.IsByRef)
342                                         m.MemberType = m.MemberType.GetElementType ();
343                                 if (optional_ns != null)
344                                         m.XmlAttributes.XmlElements.Add (optional_ns);
345                                 out_members [i + idx] = m;
346                         }
347                         return out_members;
348                 }
349
350                 XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers)
351                 {
352                         XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length];
353
354                         for (int n=0; n<headers.Length; n++)
355                         {
356                                 HeaderInfo header = headers [n];
357                                 
358                                 XmlReflectionMember m = new XmlReflectionMember ();
359                                 m.IsReturnValue = false;
360                                 m.MemberName = header.HeaderType.Name;
361                                 m.MemberType = header.HeaderType;
362
363                                 // MS.NET reflects header classes in a weird way. The root element
364                                 // name is the CLR class name unless it is specified in an XmlRootAttribute.
365                                 // The usual is to use the xml type name by default, but not in this case.
366                                 
367                                 XmlAttributes ats = new XmlAttributes (header.HeaderType);
368                                 if (ats.XmlRoot != null) {
369                                         XmlElementAttribute xe = new XmlElementAttribute ();
370                                         xe.ElementName = ats.XmlRoot.ElementName;
371                                         xe.Namespace = ats.XmlRoot.Namespace;
372                                         m.XmlAttributes = new XmlAttributes ();
373                                         m.XmlAttributes.XmlElements.Add (xe);
374                                 }
375                                 
376                                 mems [n] = m;
377                         }
378                         return mems;
379                 }
380
381                 public HeaderInfo GetHeaderInfo (Type headerType)
382                 {
383                         foreach (HeaderInfo headerInfo in Headers)
384                                 if (headerInfo.HeaderType == headerType) return headerInfo;
385                         return null;
386                 }
387                 
388                 public XmlSerializer GetBodySerializer (SoapHeaderDirection dir, bool soap12)
389                 {
390                         switch (dir) {
391                                 case SoapHeaderDirection.In: return RequestSerializer;
392                                 case SoapHeaderDirection.Out: return ResponseSerializer;
393                                 case SoapHeaderDirection.Fault: return soap12 ? Soap12Fault.Serializer : Fault.Serializer;
394                                 default: return null;
395                         }
396                 }
397                 
398                 public XmlSerializer GetHeaderSerializer (SoapHeaderDirection dir)
399                 {
400                         switch (dir) {
401                                 case SoapHeaderDirection.In: return RequestHeadersSerializer;
402                                 case SoapHeaderDirection.Out: return ResponseHeadersSerializer;
403                                 case SoapHeaderDirection.Fault: return FaultHeadersSerializer;
404                                 default: return null;
405                         }
406                 }
407                 
408                 HeaderInfo[] GetHeaders (SoapHeaderDirection dir)
409                 {
410                         switch (dir) {
411                                 case SoapHeaderDirection.In: return InHeaders;
412                                 case SoapHeaderDirection.Out: return OutHeaders;
413                                 case SoapHeaderDirection.Fault: return FaultHeaders;
414                                 default: return null;
415                         }
416                 }
417                 
418                 public object[] GetHeaderValueArray (SoapHeaderDirection dir, SoapHeaderCollection headers)
419                 {
420                         HeaderInfo[] headerInfos = GetHeaders (dir);
421                         if (headerInfos == null) return null;
422
423                         object[] hs = new object [headerInfos.Length];
424                         
425                         for (int n=0; n<headers.Count; n++) {
426                                 SoapHeader h = headers[n];
427                                 Type t = h.GetType();
428                                 for (int i=0; i<headerInfos.Length; i++)
429                                         if (headerInfos [i].HeaderType == t)
430                                                 hs [i] = h;
431                         }
432                         return hs;
433                 }
434         }
435
436         //
437         // Holds the metadata loaded from the type stub, as well as
438         // the metadata for all the methods in the type
439         //
440         internal class SoapTypeStubInfo : TypeStubInfo
441         {
442                 Hashtable[] header_serializers = new Hashtable [3];
443                 Hashtable[] header_serializers_byname = new Hashtable [3];
444                 Hashtable methods_byaction = new Hashtable (); 
445
446                 // Precomputed
447                 internal SoapParameterStyle      ParameterStyle;
448                 internal SoapExtensionRuntimeConfig[][] SoapExtensions;
449                 internal SoapBindingStyle SoapBindingStyle;
450                 internal XmlReflectionImporter  xmlImporter;
451                 internal SoapReflectionImporter soapImporter;
452
453                 public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
454                 : base (logicalTypeInfo)
455                 {
456                         xmlImporter = new XmlReflectionImporter ();
457                         soapImporter = new SoapReflectionImporter ();
458                                 
459                         if (typeof (SoapHttpClientProtocol).IsAssignableFrom (Type))
460                         {
461                                 if (Bindings.Count == 0 || ((BindingInfo)Bindings[0]).WebServiceBindingAttribute == null)
462                                         throw new InvalidOperationException ("WebServiceBindingAttribute is required on proxy class '" + Type + "'.");
463                                 if (Bindings.Count > 1)
464                                         throw new InvalidOperationException ("Only one WebServiceBinding attribute may be specified on type '" + Type + "'.");
465                         }
466
467                         object [] o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
468                         if (o.Length == 1){
469                                 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
470
471                                 ParameterStyle = a.ParameterStyle;
472                                 SoapBindingStyle = SoapBindingStyle.Document;
473                         } else {
474                                 o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
475                                 if (o.Length == 1){
476                                         SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
477                                         
478                                         ParameterStyle = SoapParameterStyle.Wrapped;
479                                         SoapBindingStyle = SoapBindingStyle.Rpc;
480                                 } else {
481                                         ParameterStyle = SoapParameterStyle.Wrapped;
482                                         SoapBindingStyle = SoapBindingStyle.Document;
483                                 }
484                         }
485                         
486                         if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
487                         
488                         xmlImporter.IncludeTypes (Type);
489                         soapImporter.IncludeTypes (Type);
490
491                         SoapExtensions = SoapExtension.GetTypeExtensions (Type);
492                 }
493
494                 internal SoapServiceRoutingStyle RoutingStyle {
495                         get { return LogicalType.RoutingStyle; }
496                 }
497
498                 public override XmlReflectionImporter XmlImporter 
499                 {
500                         get { return xmlImporter; }
501                 }
502
503                 public override SoapReflectionImporter SoapImporter 
504                 {
505                         get { return soapImporter; }
506                 }
507                 
508                 public override string ProtocolName
509                 {
510                         get { return "Soap"; }
511                 }
512                 
513                 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
514                 {
515                         SoapMethodStubInfo res = null;
516                         object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
517                         if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
518
519                         if (ats.Length == 0 && isClientProxy)
520                                 return null;
521                         else if (ats.Length == 0)
522                                 res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
523                         else
524                                 res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
525                                 
526                         methods_byaction [res.Action] = res;
527                         return res;
528                 }
529                 
530                 public SoapMethodStubInfo GetMethodForSoapAction (string name)
531                 {
532                         return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];
533                 }
534         }
535
536         internal class Soap12TypeStubInfo : SoapTypeStubInfo
537         {
538                 public Soap12TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
539                 : base (logicalTypeInfo)
540                 {
541                 }
542
543                 public override string ProtocolName
544                 {
545                         get { return "Soap12"; }
546                 }
547         }
548 }