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 		//
SoapMethodStubInfo(TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)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 
BuildRequestReflectionMembers(XmlElementAttribute optional_ns)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 
BuildResponseReflectionMembers(XmlElementAttribute optional_ns)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 
BuildHeadersReflectionMembers(HeaderInfo[] headers)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 
GetHeaderInfo(Type headerType)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 
GetBodySerializer(SoapHeaderDirection dir, bool soap12)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 
GetHeaderSerializer(SoapHeaderDirection dir)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 
GetHeaders(SoapHeaderDirection dir)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 
GetHeaderValueArray(SoapHeaderDirection dir, SoapHeaderCollection headers)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 
SoapTypeStubInfo(LogicalTypeInfo logicalTypeInfo)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 
CreateMethodStubInfo(TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)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 
GetMethodForSoapAction(string name)540 		public SoapMethodStubInfo GetMethodForSoapAction (string name)
541 		{
542 			return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];
543 		}
544 	}
545 
546 	internal class Soap12TypeStubInfo : SoapTypeStubInfo
547 	{
Soap12TypeStubInfo(LogicalTypeInfo logicalTypeInfo)548 		public Soap12TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
549 		: base (logicalTypeInfo)
550 		{
551 		}
552 
553 		public override string ProtocolName
554 		{
555 			get { return "Soap12"; }
556 		}
557 	}
558 }
559