5ae94501893e9c39945e982f158024e2156032b5
[mono.git] / mcs / class / referencesource / System.Web.Services / System / Web / Services / Description / SoapProtocolImporter.cs
1 //------------------------------------------------------------------------------
2 //  <copyright from='1997' to='2001' company='Microsoft Corporation'>           
3 //     Copyright (c) Microsoft Corporation. All Rights Reserved.                
4 //     Information Contained Herein is Proprietary and Confidential.            
5 //  </copyright>                                                                
6 //------------------------------------------------------------------------------
7 namespace System.Web.Services.Description {
8
9     using System.Web.Services;
10     using System.Web.Services.Protocols;
11     using System.Xml;
12     using System.Xml.Serialization;
13     using System.Xml.Serialization.Advanced;
14     using System.Xml.Schema;
15     using System.Collections;
16     using System;
17     using System.Data;
18     using System.Data.Design;
19     using System.Reflection;
20     using System.CodeDom;
21     using System.CodeDom.Compiler;
22     using System.Web.Services.Configuration;
23     using System.Diagnostics;
24     using System.ComponentModel;
25     using System.Security.Permissions;
26     using System.Globalization;
27     using System.Threading;
28     
29     internal class SoapParameters {
30         XmlMemberMapping ret;
31         ArrayList parameters = new ArrayList();
32         ArrayList inParameters = new ArrayList();
33         ArrayList outParameters = new ArrayList();
34         int checkSpecifiedCount;
35         int inCheckSpecifiedCount;
36         int outCheckSpecifiedCount;
37
38         internal SoapParameters(XmlMembersMapping request, XmlMembersMapping response, string[] parameterOrder, CodeIdentifiers identifiers) {
39             ArrayList requestList = new ArrayList();
40             ArrayList responseList = new ArrayList();
41
42             AddMappings(requestList, request);
43             if (response != null) AddMappings(responseList, response);
44
45             if (parameterOrder != null) {
46                 for (int i = 0; i < parameterOrder.Length; i++) {
47                     string elementName = parameterOrder[i];
48                     XmlMemberMapping requestMapping = FindMapping(requestList, elementName);
49                     SoapParameter parameter = new SoapParameter();
50                     if (requestMapping != null) {
51                         if (RemoveByRefMapping(responseList, requestMapping))
52                             parameter.codeFlags = CodeFlags.IsByRef;
53                         parameter.mapping = requestMapping;
54                         requestList.Remove(requestMapping);
55                         AddParameter(parameter);
56                     }
57                     else {
58                         XmlMemberMapping responseMapping = FindMapping(responseList, elementName);
59                         if (responseMapping != null) {
60                             parameter.codeFlags = CodeFlags.IsOut;
61                             parameter.mapping = responseMapping;
62                             responseList.Remove(responseMapping);
63                             AddParameter(parameter);
64                         }
65                     }
66                 }
67             }
68
69             foreach (XmlMemberMapping requestMapping in requestList) {
70                 SoapParameter parameter = new SoapParameter();
71                 if (RemoveByRefMapping(responseList, requestMapping))
72                     parameter.codeFlags = CodeFlags.IsByRef;
73                 parameter.mapping = requestMapping;
74                 AddParameter(parameter);
75             }
76
77             if (responseList.Count > 0) {
78                 if (!((XmlMemberMapping) responseList[0]).CheckSpecified) {
79                     ret = (XmlMemberMapping)responseList[0];
80                     responseList.RemoveAt(0);
81                 }
82                 foreach (XmlMemberMapping responseMapping in responseList) {
83                     SoapParameter parameter = new SoapParameter();
84                     parameter.mapping = responseMapping;
85                     parameter.codeFlags = CodeFlags.IsOut;
86                     AddParameter(parameter);
87                 }
88             }
89
90             foreach (SoapParameter parameter in parameters) {
91                 parameter.name = identifiers.MakeUnique(CodeIdentifier.MakeValid(parameter.mapping.MemberName));
92             }
93         }
94
95         void AddParameter(SoapParameter parameter) {
96             parameters.Add(parameter);
97             if (parameter.mapping.CheckSpecified) {
98                 checkSpecifiedCount++;
99             }
100             if (parameter.IsByRef) {
101                 inParameters.Add(parameter);
102                 outParameters.Add(parameter);
103                 if (parameter.mapping.CheckSpecified) {
104                     inCheckSpecifiedCount++;
105                     outCheckSpecifiedCount++;
106                 }
107             } else if (parameter.IsOut) {
108                 outParameters.Add(parameter);
109                 if (parameter.mapping.CheckSpecified)
110                     outCheckSpecifiedCount++;
111             }
112             else {
113                 inParameters.Add(parameter);
114                 if (parameter.mapping.CheckSpecified)
115                     inCheckSpecifiedCount++;
116             }
117         }
118
119         static bool RemoveByRefMapping(ArrayList responseList, XmlMemberMapping requestMapping) {
120             XmlMemberMapping responseMapping = FindMapping(responseList, requestMapping.ElementName);
121             if (responseMapping == null) return false;
122             if (requestMapping.TypeFullName != responseMapping.TypeFullName) return false;
123             if (requestMapping.Namespace != responseMapping.Namespace) return false;
124             if (requestMapping.MemberName != responseMapping.MemberName) return false;
125             responseList.Remove(responseMapping);
126             return true;
127         }
128
129         static void AddMappings(ArrayList mappingsList, XmlMembersMapping mappings) {
130             for (int i = 0; i < mappings.Count; i++) {
131                 mappingsList.Add(mappings[i]);
132             }
133         }
134
135         static XmlMemberMapping FindMapping(ArrayList mappingsList, string elementName) {
136             foreach (XmlMemberMapping mapping in mappingsList)
137                 if (mapping.ElementName == elementName)
138                     return mapping;
139             return null;
140         }
141
142         internal XmlMemberMapping Return {
143             get { return ret; }
144         }
145
146         internal IList Parameters {
147             get { return parameters; }
148         }
149
150         internal IList InParameters {
151             get { return inParameters; }
152         }
153
154         internal IList OutParameters {
155             get { return outParameters; }
156         }
157         
158         internal int CheckSpecifiedCount {
159             get { return checkSpecifiedCount; }
160         }
161         
162         internal int InCheckSpecifiedCount {
163             get { return inCheckSpecifiedCount; }
164         }
165         
166         internal int OutCheckSpecifiedCount {
167             get { return outCheckSpecifiedCount; }
168         }
169     }
170
171     internal class SoapParameter {
172         internal CodeFlags codeFlags;
173         internal string name;
174         internal XmlMemberMapping mapping;
175         internal string specifiedName;
176
177         internal bool IsOut {
178             get { return (codeFlags & CodeFlags.IsOut) != 0; }
179         }
180
181         internal bool IsByRef {
182             get { return (codeFlags & CodeFlags.IsByRef) != 0; }
183         }
184
185         internal static string[] GetTypeFullNames(IList parameters, int specifiedCount, CodeDomProvider codeProvider) {
186             string[] typeFullNames = new string[parameters.Count + specifiedCount];
187             GetTypeFullNames(parameters, typeFullNames, 0, specifiedCount, codeProvider);
188             return typeFullNames;
189         }
190
191         internal static void GetTypeFullNames(IList parameters, string[] typeFullNames, int start, int specifiedCount, CodeDomProvider codeProvider) {
192             int specified = 0;
193             for (int i = 0; i < parameters.Count; i++) {
194                 typeFullNames[i + start + specified] = WebCodeGenerator.FullTypeName(((SoapParameter)parameters[i]).mapping, codeProvider);
195                 if (((SoapParameter) parameters[i]).mapping.CheckSpecified) {
196                     specified++;
197                     typeFullNames[i + start + specified] = typeof(bool).FullName;
198                 }
199             }
200         }
201
202         internal static string[] GetNames(IList parameters, int specifiedCount) {
203             string[] names = new string[parameters.Count + specifiedCount];
204             GetNames(parameters, names, 0, specifiedCount);
205             return names;
206         }
207
208         internal static void GetNames(IList parameters, string[] names, int start, int specifiedCount) {
209             int specified = 0;
210             for (int i = 0; i < parameters.Count; i++) {
211                 names[i + start + specified] = ((SoapParameter)parameters[i]).name;
212                 if (((SoapParameter) parameters[i]).mapping.CheckSpecified) {
213                     specified++;
214                     names[i + start + specified] = ((SoapParameter) parameters[i]).specifiedName;
215                 }
216             }
217         }
218
219         internal static CodeFlags[] GetCodeFlags(IList parameters, int specifiedCount) {
220             CodeFlags[] codeFlags = new CodeFlags[parameters.Count + specifiedCount];
221             GetCodeFlags(parameters, codeFlags, 0, specifiedCount);
222             return codeFlags;
223         }
224
225         internal static void GetCodeFlags(IList parameters, CodeFlags[] codeFlags, int start, int specifiedCount) {
226             int specified = 0;
227             for (int i = 0; i < parameters.Count; i++) {
228                 codeFlags[i + start + specified] = ((SoapParameter)parameters[i]).codeFlags;
229                 if (((SoapParameter) parameters[i]).mapping.CheckSpecified) {
230                     specified++;
231                     codeFlags[i + start + specified] = ((SoapParameter) parameters[i]).codeFlags;
232                 }
233             }
234         }
235     }
236
237     internal class GlobalSoapHeader {
238         internal string fieldName;        
239         internal XmlTypeMapping mapping;  
240         internal bool isEncoded;      
241     }
242     
243     internal class LocalSoapHeader {
244         internal SoapHeaderDirection direction;        
245         internal string fieldName;        
246     }
247             
248     /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter"]/*' />
249     /// <devdoc>
250     ///    <para>[To be supplied.]</para>
251     /// </devdoc>
252     [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
253     [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
254     public class SoapProtocolImporter : ProtocolImporter {
255         XmlSchemaImporter xmlImporter;
256         XmlCodeExporter xmlExporter;
257         SoapSchemaImporter soapImporter;
258         SoapCodeExporter soapExporter;
259         ArrayList xmlMembers = new ArrayList();        
260         ArrayList soapMembers = new ArrayList();
261         Hashtable headers = new Hashtable();
262         Hashtable classHeaders = new Hashtable();
263         ArrayList propertyNames = new ArrayList();
264         ArrayList propertyValues = new ArrayList();
265         SoapExtensionImporter[] extensions;
266         SoapTransportImporter transport;
267         SoapBinding soapBinding;
268         ArrayList codeClasses = new ArrayList();
269         static TypedDataSetSchemaImporterExtension typedDataSetSchemaImporterExtension;
270
271         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.ProtocolName"]/*' />
272         /// <devdoc>
273         ///    <para>[To be supplied.]</para>
274         /// </devdoc>
275         public override string ProtocolName {
276             get { return "Soap"; }
277         }
278
279         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.SoapBinding"]/*' />
280         /// <devdoc>
281         ///    <para>[To be supplied.]</para>
282         /// </devdoc>
283         public SoapBinding SoapBinding {
284             get { return soapBinding; }
285         }
286
287         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.SoapImporter"]/*' />
288         /// <devdoc>
289         ///    <para>[To be supplied.]</para>
290         /// </devdoc>
291         public SoapSchemaImporter SoapImporter {
292             get { return soapImporter; }
293         }
294
295         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.XmlImporter"]/*' />
296         /// <devdoc>
297         ///    <para>[To be supplied.]</para>
298         /// </devdoc>
299         public XmlSchemaImporter XmlImporter {
300             get { return xmlImporter; }
301         }
302
303         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.XmlExporter"]/*' />
304         /// <devdoc>
305         ///    <para>[To be supplied.]</para>
306         /// </devdoc>
307         public XmlCodeExporter XmlExporter {
308             get { return xmlExporter; }
309         }
310
311         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.SoapExporter"]/*' />
312         /// <devdoc>
313         ///    <para>[To be supplied.]</para>
314         /// </devdoc>
315         public SoapCodeExporter SoapExporter {
316             get { return soapExporter; }
317         }
318
319         static TypedDataSetSchemaImporterExtension TypedDataSetSchemaImporterExtension {
320             get {
321                 if (typedDataSetSchemaImporterExtension == null) {
322                     typedDataSetSchemaImporterExtension = new TypedDataSetSchemaImporterExtension();
323                 }
324                 return typedDataSetSchemaImporterExtension;
325             }
326         }
327
328         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.BeginNamespace"]/*' />
329         /// <devdoc>
330         ///    <para>[To be supplied.]</para>
331         /// </devdoc>
332         protected override void BeginNamespace() {
333             try {
334                 MethodNames.Clear();
335                 ExtraCodeClasses.Clear();
336                 soapImporter = new SoapSchemaImporter(AbstractSchemas, ServiceImporter.CodeGenerationOptions, ImportContext);
337                 xmlImporter = new XmlSchemaImporter(ConcreteSchemas, ServiceImporter.CodeGenerationOptions, ServiceImporter.CodeGenerator, ImportContext);
338                 foreach (Type extensionType in ServiceImporter.Extensions) {
339                     xmlImporter.Extensions.Add(extensionType.FullName, extensionType);
340                 }
341                 // use cached version of typed DataSetSchemaImporterExtension for /sharetypes feature
342                 // 
343                 xmlImporter.Extensions.Add(TypedDataSetSchemaImporterExtension);
344                 xmlImporter.Extensions.Add(new DataSetSchemaImporterExtension());
345                 xmlExporter = new XmlCodeExporter(this.CodeNamespace, ServiceImporter.CodeCompileUnit, ServiceImporter.CodeGenerator, ServiceImporter.CodeGenerationOptions, ExportContext);
346                 soapExporter = new SoapCodeExporter(this.CodeNamespace, null, ServiceImporter.CodeGenerator, ServiceImporter.CodeGenerationOptions, ExportContext);
347             }
348             catch (Exception e) {
349                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
350                     throw;
351                 }
352                 throw new InvalidOperationException(Res.GetString(Res.InitFailed), e);
353             }
354         }
355
356         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.EndNamespace"]/*' />
357         /// <devdoc>
358         ///    <para>[To be supplied.]</para>
359         /// </devdoc>
360         protected override void EndNamespace() {
361             // need to preprocess all exported schemas to make sure that IXmlSerializable schemas are Merged and the resulting set is valid
362             ConcreteSchemas.Compile(null, false);
363
364             foreach (GlobalSoapHeader soapHeader in headers.Values) {
365                 if (soapHeader.isEncoded)
366                     soapExporter.ExportTypeMapping(soapHeader.mapping);
367                 else
368                     xmlExporter.ExportTypeMapping(soapHeader.mapping);
369             }
370
371             foreach (XmlMembersMapping member in xmlMembers)
372                 xmlExporter.ExportMembersMapping(member);
373
374             foreach (XmlMembersMapping member in soapMembers)
375                 soapExporter.ExportMembersMapping(member);
376
377             // NOTE, Microsoft, we are sharing the SoapInclude and XmlInclude attributes of the 
378             // class among ALL classes generated, This is probably OK, since doing to per 
379             // class would probably result in the same set of includes if the user
380             // has object as a return value (meaning 'all' types are OK).
381             foreach (CodeTypeDeclaration codeClass in codeClasses) {
382                 foreach (CodeAttributeDeclaration attribute in xmlExporter.IncludeMetadata) {
383                     codeClass.CustomAttributes.Add(attribute);
384                 }
385                 foreach (CodeAttributeDeclaration attribute in soapExporter.IncludeMetadata) {
386                     codeClass.CustomAttributes.Add(attribute);
387                 }
388             }
389             foreach (CodeTypeDeclaration declaration in ExtraCodeClasses) {
390                 this.CodeNamespace.Types.Add(declaration);
391             }
392             CodeGenerator.ValidateIdentifiers(CodeNamespace);
393         }
394
395         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.IsBindingSupported"]/*' />
396         /// <devdoc>
397         ///    <para>[To be supplied.]</para>
398         /// </devdoc>
399         protected override bool IsBindingSupported() {
400             SoapBinding soapBinding = (SoapBinding)Binding.Extensions.Find(typeof(SoapBinding));
401             if (soapBinding == null || soapBinding.GetType() != typeof(SoapBinding)) return false;
402
403             if (GetTransport(soapBinding.Transport) == null) {
404                 UnsupportedBindingWarning(Res.GetString(Res.ThereIsNoSoapTransportImporterThatUnderstands1, soapBinding.Transport));
405                 return false;
406             }
407
408             return true;
409         }
410
411         internal SoapTransportImporter GetTransport(string transport) {
412             foreach (Type type in WebServicesSection.Current.SoapTransportImporters)
413             {
414                 SoapTransportImporter transportImporter = (SoapTransportImporter)Activator.CreateInstance(type);
415                 transportImporter.ImportContext = this;
416                 if (transportImporter.IsSupportedTransport(transport)) return transportImporter;
417             }
418             return null;
419         }
420
421         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.BeginClass"]/*' />
422         /// <devdoc>
423         ///    <para>[To be supplied.]</para>
424         /// </devdoc>
425         protected override CodeTypeDeclaration BeginClass() {
426             MethodNames.Clear();
427
428             soapBinding = (SoapBinding)Binding.Extensions.Find(typeof(SoapBinding));
429             transport = GetTransport(soapBinding.Transport);
430
431             Type[] requiredTypes = new Type[] { typeof(SoapDocumentMethodAttribute), typeof(XmlAttributeAttribute), typeof(WebService), typeof(Object), typeof(DebuggerStepThroughAttribute), typeof(DesignerCategoryAttribute) };
432             WebCodeGenerator.AddImports(this.CodeNamespace, WebCodeGenerator.GetNamespacesForTypes(requiredTypes));
433             CodeFlags flags = 0;
434             if (Style == ServiceDescriptionImportStyle.Server)
435                 flags = CodeFlags.IsAbstract;
436             else if (Style == ServiceDescriptionImportStyle.ServerInterface)
437                 flags = CodeFlags.IsInterface;
438             CodeTypeDeclaration codeClass = WebCodeGenerator.CreateClass(this.ClassName, null, 
439                 new string[0], null, CodeFlags.IsPublic | flags,
440                 ServiceImporter.CodeGenerator.Supports(GeneratorSupport.PartialTypes));
441
442             codeClass.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true));
443             if (Style == ServiceDescriptionImportStyle.Client) {
444                 codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DebuggerStepThroughAttribute).FullName));
445                 codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DesignerCategoryAttribute).FullName, new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression("code")) }));
446             }
447             else if (Style == ServiceDescriptionImportStyle.Server) {
448                 CodeAttributeDeclaration webService = new CodeAttributeDeclaration(typeof(WebServiceAttribute).FullName);
449                 string targetNs = Service != null ? Service.ServiceDescription.TargetNamespace : Binding.ServiceDescription.TargetNamespace;
450                 webService.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(targetNs)));
451                 codeClass.CustomAttributes.Add(webService);
452             }
453
454             CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(WebServiceBindingAttribute).FullName);
455             attribute.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(XmlConvert.DecodeName(Binding.Name))));
456             attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(Binding.ServiceDescription.TargetNamespace)));
457
458             codeClass.CustomAttributes.Add(attribute);
459
460             codeClasses.Add(codeClass);
461             classHeaders.Clear();
462             return codeClass;
463         }
464
465         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.EndClass"]/*' />
466         /// <devdoc>
467         ///    <para>[To be supplied.]</para>
468         /// </devdoc>
469         protected override void EndClass() { 
470             if (transport != null)
471                 transport.ImportClass();
472             soapBinding = null;
473         }
474
475         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.IsOperationFlowSupported"]/*' />
476         /// <devdoc>
477         ///    <para>[To be supplied.]</para>
478         /// </devdoc>
479         protected override bool IsOperationFlowSupported(OperationFlow flow) {
480             return flow == OperationFlow.OneWay || flow == OperationFlow.RequestResponse;
481         }
482
483         void BeginMetadata() {
484             propertyNames.Clear();
485             propertyValues.Clear();
486         }
487
488         bool MetadataPropertiesAdded {
489             get { return propertyNames.Count > 0; }
490         }
491
492         void AddMetadataProperty(string name, object value) {
493             AddMetadataProperty(name, new CodePrimitiveExpression(value));
494         }
495
496         void AddMetadataProperty(string name, CodeExpression expr) {
497             propertyNames.Add(name);
498             propertyValues.Add(expr);
499         }
500
501         void EndMetadata(CodeAttributeDeclarationCollection metadata, Type attributeType, string parameter) {
502             CodeExpression[] parameters;
503             if (parameter == null) {
504                 parameters = new CodeExpression[0];
505             }
506             else {
507                 parameters = new CodeExpression[1] { new CodePrimitiveExpression(parameter) };
508             }
509             WebCodeGenerator.AddCustomAttribute(metadata, attributeType, parameters, 
510                                   (string[])propertyNames.ToArray(typeof(string)), 
511                                   (CodeExpression[])propertyValues.ToArray(typeof(CodeExpression)));
512         }
513
514         void GenerateExtensionMetadata(CodeAttributeDeclarationCollection metadata) {
515             if (extensions == null) {
516                 TypeElementCollection extensionTypes = WebServicesSection.Current.SoapExtensionImporterTypes;
517                 extensions = new SoapExtensionImporter[extensionTypes.Count];
518                 for (int i = 0; i < extensions.Length; i++) {
519                     SoapExtensionImporter extension = (SoapExtensionImporter)Activator.CreateInstance(extensionTypes[i].Type);
520                     extension.ImportContext = this;
521                     extensions[i] = extension;
522                 }
523             }
524             foreach (SoapExtensionImporter extension in extensions) {
525                 extension.ImportMethod(metadata);
526             }
527         }
528
529         void PrepareHeaders(MessageBinding messageBinding) {
530             // By default, map all headers to properties on the generated class
531             // ExtensionImporters can modify this behavior by clearing the flag
532             SoapHeaderBinding[] headers = (SoapHeaderBinding[])messageBinding.Extensions.FindAll(typeof(SoapHeaderBinding));
533             foreach (SoapHeaderBinding header in headers) {
534                 header.MapToProperty = true;
535             }
536         }
537
538         void GenerateHeaders(CodeAttributeDeclarationCollection metadata, SoapBindingUse use, bool rpc, MessageBinding requestMessage, MessageBinding responseMessage) { 
539             Hashtable localHeaders = new Hashtable();
540
541             for (int i = 0; i < 2; ++i) {
542                 MessageBinding messageBinding;
543                 SoapHeaderDirection direction;
544                 if (i == 0) {
545                     messageBinding = requestMessage;
546                     direction = SoapHeaderDirection.In;
547                 }
548                 else if (responseMessage != null) {
549                     messageBinding = responseMessage;
550                     direction = SoapHeaderDirection.Out;
551                 }
552                 else
553                     continue;
554
555                 SoapHeaderBinding[] headerBindings = (SoapHeaderBinding[])messageBinding.Extensions.FindAll(typeof(SoapHeaderBinding));
556                 foreach (SoapHeaderBinding header in headerBindings) {
557                     // Skip headers which should not be mapped to properties (extension importers can control this)
558                     if (!header.MapToProperty) continue;
559
560                     if (use != header.Use) throw new InvalidOperationException(Res.GetString(Res.WebDescriptionHeaderAndBodyUseMismatch));
561                     if (use == SoapBindingUse.Encoded && !IsSoapEncodingPresent(header.Encoding) )
562                         throw new InvalidOperationException(Res.GetString(Res.WebUnknownEncodingStyle, header.Encoding));
563
564                     Message message = ServiceDescriptions.GetMessage(header.Message);
565                     if (message == null) throw new InvalidOperationException(Res.GetString(Res.MissingMessage2, header.Message.Name, header.Message.Namespace));
566
567                     MessagePart part = message.FindPartByName(header.Part);
568                     if (part == null) throw new InvalidOperationException(Res.GetString(Res.MissingMessagePartForMessageFromNamespace3, part.Name, header.Message.Name, header.Message.Namespace));
569
570                     XmlTypeMapping mapping;
571                     string key;
572                     if (use == SoapBindingUse.Encoded) {
573                         if (part.Type.IsEmpty) throw new InvalidOperationException(Res.GetString(Res.WebDescriptionPartTypeRequired, part.Name, header.Message.Name, header.Message.Namespace));
574                         if (!part.Element.IsEmpty) UnsupportedOperationBindingWarning(Res.GetString(Res.WebDescriptionPartElementWarning, part.Name, header.Message.Name, header.Message.Namespace));
575                         mapping = soapImporter.ImportDerivedTypeMapping(part.Type, typeof(SoapHeader), true);
576                         key = "type=" + part.Type.ToString();
577                     }
578                     else {
579                         if (part.Element.IsEmpty) throw new InvalidOperationException(Res.GetString(Res.WebDescriptionPartElementRequired, part.Name, header.Message.Name, header.Message.Namespace));
580                         if (!part.Type.IsEmpty) UnsupportedOperationBindingWarning(Res.GetString(Res.WebDescriptionPartTypeWarning, part.Name, header.Message.Name, header.Message.Namespace));
581                         mapping = xmlImporter.ImportDerivedTypeMapping(part.Element, typeof(SoapHeader), true);
582                         key = "element=" + part.Element.ToString();
583                     }
584                     LocalSoapHeader localHeader = (LocalSoapHeader)localHeaders[key];
585                     if (localHeader == null) {
586                         GlobalSoapHeader globalHeader = (GlobalSoapHeader)classHeaders[key];
587                         if (globalHeader == null) {
588                             globalHeader = new GlobalSoapHeader();
589                             globalHeader.isEncoded = use == SoapBindingUse.Encoded;
590                             string fieldName = CodeIdentifier.MakeValid(mapping.ElementName);
591                             if (fieldName == mapping.TypeName) fieldName += "Value";
592                             fieldName = MethodNames.AddUnique(fieldName, mapping);
593                             globalHeader.fieldName = fieldName;
594                             WebCodeGenerator.AddMember(CodeTypeDeclaration, mapping.TypeFullName, globalHeader.fieldName, null, null, CodeFlags.IsPublic, ServiceImporter.CodeGenerationOptions);
595                             globalHeader.mapping = mapping;
596                             classHeaders.Add(key, globalHeader);
597                             if (headers[key] == null)
598                                 headers.Add(key, globalHeader);
599                         }
600
601                         localHeader = new LocalSoapHeader();
602                         localHeader.fieldName = globalHeader.fieldName;
603                         localHeader.direction = direction;
604                         localHeaders.Add(key, localHeader);
605                     }
606                     else {
607                         if (localHeader.direction != direction)
608                             localHeader.direction = SoapHeaderDirection.InOut;
609                     }
610                 }
611             }
612
613             foreach (LocalSoapHeader soapHeader in localHeaders.Values) {
614                 BeginMetadata();
615                 if (soapHeader.direction == SoapHeaderDirection.Out) {
616                     AddMetadataProperty("Direction", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapHeaderDirection).FullName), SoapHeaderDirection.Out.ToString()));
617                 }
618                 else if (soapHeader.direction == SoapHeaderDirection.InOut) { 
619                     AddMetadataProperty("Direction", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapHeaderDirection).FullName), SoapHeaderDirection.InOut.ToString()));
620                 }
621
622                 EndMetadata(metadata, typeof(SoapHeaderAttribute), soapHeader.fieldName);
623             }
624         }
625
626         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.GenerateMethod"]/*' />
627         /// <devdoc>
628         ///    <para>[To be supplied.]</para>
629         /// </devdoc>
630         protected override CodeMemberMethod GenerateMethod() {
631             Message requestMessage;
632             Message responseMessage;
633             string[] parameterOrder;
634             SoapBodyBinding soapRequestBinding;
635             SoapBodyBinding soapResponseBinding;
636             MessageBinding requestBinding;
637             MessageBinding responseBinding;
638
639             SoapOperationBinding soapOperationBinding = (SoapOperationBinding)this.OperationBinding.Extensions.Find(typeof(SoapOperationBinding));
640             if (soapOperationBinding == null) throw OperationBindingSyntaxException(Res.GetString(Res.MissingSoapOperationBinding0));
641
642             SoapBindingStyle soapBindingStyle = soapOperationBinding.Style;
643             if (soapBindingStyle == SoapBindingStyle.Default)
644                 soapBindingStyle = SoapBinding.Style;
645             if (soapBindingStyle == SoapBindingStyle.Default)
646                 soapBindingStyle = SoapBindingStyle.Document;
647
648             parameterOrder = this.Operation.ParameterOrder;
649
650             requestMessage = this.InputMessage;
651             requestBinding = this.OperationBinding.Input;
652             soapRequestBinding = (SoapBodyBinding)this.OperationBinding.Input.Extensions.Find(typeof(SoapBodyBinding));
653             if (soapRequestBinding == null) {
654                 UnsupportedOperationBindingWarning(Res.GetString(Res.MissingSoapBodyInputBinding0));
655                 return null;
656             }
657
658             if (this.Operation.Messages.Output != null) {
659                 responseMessage = this.OutputMessage;
660                 responseBinding = this.OperationBinding.Output;
661                 soapResponseBinding = (SoapBodyBinding)this.OperationBinding.Output.Extensions.Find(typeof(SoapBodyBinding));
662                 if (soapResponseBinding == null) {
663                     UnsupportedOperationBindingWarning(Res.GetString(Res.MissingSoapBodyOutputBinding0));
664                     return null;
665                 }
666             }
667             else {
668                 responseMessage = null;
669                 responseBinding = null;
670                 soapResponseBinding = null;
671             }
672
673             CodeAttributeDeclarationCollection metadata = new CodeAttributeDeclarationCollection();
674
675             PrepareHeaders(requestBinding);
676             if (responseBinding != null) PrepareHeaders(responseBinding);
677
678             string requestMessageName;
679             string responseMessageName = null;
680
681             requestMessageName = !String.IsNullOrEmpty(requestBinding.Name) && soapBindingStyle != SoapBindingStyle.Rpc ? requestBinding.Name : this.Operation.Name; // per WSDL 1.1 sec 3.5
682             requestMessageName = XmlConvert.DecodeName(requestMessageName);
683
684             if (responseBinding != null) {
685                 responseMessageName = !String.IsNullOrEmpty(responseBinding.Name) && soapBindingStyle != SoapBindingStyle.Rpc ? responseBinding.Name : this.Operation.Name + "Response"; // per WSDL 1.1 sec 3.5
686                 responseMessageName = XmlConvert.DecodeName(responseMessageName);
687             }
688
689             GenerateExtensionMetadata(metadata);
690             GenerateHeaders(metadata, soapRequestBinding.Use, soapBindingStyle == SoapBindingStyle.Rpc, requestBinding, responseBinding);
691
692             MessagePart[] requestParts = GetMessageParts(requestMessage, soapRequestBinding);
693             bool hasWrapper;
694             if (!CheckMessageStyles(MethodName, requestParts, soapRequestBinding, soapBindingStyle, out hasWrapper))
695                 return null;
696
697             MessagePart[] responseParts = null;
698             if (responseMessage != null) {
699                 responseParts = GetMessageParts(responseMessage, soapResponseBinding);
700                 bool responseHasWrapper;
701                 if (!CheckMessageStyles(MethodName, responseParts, soapResponseBinding, soapBindingStyle, out responseHasWrapper)) 
702                     return null;
703
704                 // since we're using a potentially inaccurate heuristic to determine whether there's a wrapper,
705                 // if we disagree about the request and response we should assume there isn't a wrapper.
706                 if (hasWrapper != responseHasWrapper)
707                     hasWrapper = false;
708             }
709
710             bool wrapperNamesMatter = (soapBindingStyle != SoapBindingStyle.Rpc && hasWrapper) || (soapRequestBinding.Use == SoapBindingUse.Literal && soapBindingStyle == SoapBindingStyle.Rpc);
711
712             XmlMembersMapping request = ImportMessage(requestMessageName, requestParts, soapRequestBinding, soapBindingStyle, hasWrapper);
713             if (request == null) return null;
714
715             XmlMembersMapping response = null;
716
717             if (responseMessage != null) {
718                 response = ImportMessage(responseMessageName, responseParts, soapResponseBinding, soapBindingStyle, hasWrapper);
719                 if (response == null) return null;
720             }
721
722             string methodName = CodeIdentifier.MakeValid(XmlConvert.DecodeName(this.Operation.Name));
723             if (ClassName == methodName) {
724                 methodName = "Call" + methodName;
725             }
726             string uniqueMethodName = MethodNames.AddUnique(CodeIdentifier.MakeValid(XmlConvert.DecodeName(methodName)), this.Operation);
727             bool differentNames = methodName != uniqueMethodName;
728
729             CodeIdentifiers localIdentifiers = new CodeIdentifiers(false);
730             localIdentifiers.AddReserved(uniqueMethodName);
731
732             SoapParameters parameters = new SoapParameters(request, response, parameterOrder, MethodNames);
733
734             foreach (SoapParameter param in parameters.Parameters) {
735                 if ((param.IsOut || param.IsByRef) && !ServiceImporter.CodeGenerator.Supports(GeneratorSupport.ReferenceParameters)) {
736                     UnsupportedOperationWarning(Res.GetString(Res.CodeGenSupportReferenceParameters, ServiceImporter.CodeGenerator.GetType().Name));
737                     return null;
738                 }
739                 param.name = localIdentifiers.AddUnique(param.name, null);
740                 if (param.mapping.CheckSpecified)
741                     param.specifiedName = localIdentifiers.AddUnique(param.name + "Specified", null);
742             }
743
744             if (!(Style == ServiceDescriptionImportStyle.Client) || differentNames) {
745                 BeginMetadata();
746                 if (differentNames) AddMetadataProperty("MessageName", uniqueMethodName);
747                 EndMetadata(metadata, typeof(WebMethodAttribute), null);
748             }
749
750             BeginMetadata();
751             if (wrapperNamesMatter && request.ElementName.Length > 0 && request.ElementName != uniqueMethodName)
752                 AddMetadataProperty("RequestElementName", request.ElementName);
753             if (request.Namespace != null)
754                 AddMetadataProperty("RequestNamespace", request.Namespace);
755             if (response == null) {
756                 AddMetadataProperty("OneWay", true);                    
757             }
758             else {
759                 if (wrapperNamesMatter && response.ElementName.Length > 0 && response.ElementName != (uniqueMethodName + "Response"))
760                     AddMetadataProperty("ResponseElementName", response.ElementName);
761                 if (response.Namespace != null)
762                     AddMetadataProperty("ResponseNamespace", response.Namespace);                                     
763             }
764
765             if (soapBindingStyle == SoapBindingStyle.Rpc) {
766                 if (soapRequestBinding.Use != SoapBindingUse.Encoded) {
767                     AddMetadataProperty("Use", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapBindingUse).FullName), Enum.Format(typeof(SoapBindingUse), soapRequestBinding.Use, "G")));
768                 }
769                 EndMetadata(metadata, typeof(SoapRpcMethodAttribute), soapOperationBinding.SoapAction);
770             }
771             else {
772                 AddMetadataProperty("Use", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapBindingUse).FullName), Enum.Format(typeof(SoapBindingUse), soapRequestBinding.Use, "G")));
773                 AddMetadataProperty("ParameterStyle", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapParameterStyle).FullName), Enum.Format(typeof(SoapParameterStyle), hasWrapper ? SoapParameterStyle.Wrapped : SoapParameterStyle.Bare, "G")));
774                 EndMetadata(metadata, typeof(SoapDocumentMethodAttribute), soapOperationBinding.SoapAction);
775             }
776             IsEncodedBinding = IsEncodedBinding || (soapRequestBinding.Use == SoapBindingUse.Encoded);
777
778             CodeAttributeDeclarationCollection[] paramsMetadata = new CodeAttributeDeclarationCollection[parameters.Parameters.Count + parameters.CheckSpecifiedCount];
779             int j = 0;
780             CodeAttributeDeclaration ignoreAttribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName);
781             foreach (SoapParameter parameter in parameters.Parameters) {
782                 paramsMetadata[j] = new CodeAttributeDeclarationCollection();
783                 if (soapRequestBinding.Use == SoapBindingUse.Encoded)
784                     soapExporter.AddMappingMetadata(paramsMetadata[j], parameter.mapping, parameter.name != parameter.mapping.MemberName);
785                 else {
786                     string ns = soapBindingStyle == SoapBindingStyle.Rpc ? parameter.mapping.Namespace : parameter.IsOut ? response.Namespace : request.Namespace;
787                     bool forceUseMemberName = parameter.name != parameter.mapping.MemberName;
788                     xmlExporter.AddMappingMetadata(paramsMetadata[j], parameter.mapping,  ns, forceUseMemberName);
789                     if (parameter.mapping.CheckSpecified) {
790                         j++;
791                         paramsMetadata[j] = new CodeAttributeDeclarationCollection();
792                         xmlExporter.AddMappingMetadata(paramsMetadata[j], parameter.mapping, ns, parameter.specifiedName != parameter.mapping.MemberName + "Specified");
793                         paramsMetadata[j].Add(ignoreAttribute);
794                     }
795                 }
796                 if (paramsMetadata[j].Count > 0  && !ServiceImporter.CodeGenerator.Supports(GeneratorSupport.ParameterAttributes)) {
797                     UnsupportedOperationWarning(Res.GetString(Res.CodeGenSupportParameterAttributes, ServiceImporter.CodeGenerator.GetType().Name));
798                     return null;
799                 }
800                 j++;
801             }
802
803             CodeFlags[] parameterFlags = SoapParameter.GetCodeFlags(parameters.Parameters, parameters.CheckSpecifiedCount);
804             string[] parameterTypes = SoapParameter.GetTypeFullNames(parameters.Parameters, parameters.CheckSpecifiedCount, ServiceImporter.CodeGenerator);
805             string returnType = parameters.Return == null ? typeof(void).FullName : WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator);
806
807             CodeMemberMethod mainCodeMethod = WebCodeGenerator.AddMethod(this.CodeTypeDeclaration, methodName, 
808                                         parameterFlags, 
809                                         parameterTypes,
810                                         SoapParameter.GetNames(parameters.Parameters, parameters.CheckSpecifiedCount),
811                                         paramsMetadata,
812                                         returnType,
813                                         metadata, 
814                                         CodeFlags.IsPublic | (Style == ServiceDescriptionImportStyle.Client ? 0 : CodeFlags.IsAbstract));
815
816             mainCodeMethod.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true));
817
818             if (parameters.Return != null) {
819                 if (soapRequestBinding.Use == SoapBindingUse.Encoded)
820                     soapExporter.AddMappingMetadata(mainCodeMethod.ReturnTypeCustomAttributes, parameters.Return, parameters.Return.ElementName != uniqueMethodName + "Result");
821                 else
822                     xmlExporter.AddMappingMetadata(mainCodeMethod.ReturnTypeCustomAttributes, parameters.Return, response.Namespace, parameters.Return.ElementName != uniqueMethodName + "Result");
823
824                 if (mainCodeMethod.ReturnTypeCustomAttributes.Count != 0 && !ServiceImporter.CodeGenerator.Supports(GeneratorSupport.ReturnTypeAttributes)) {
825                     UnsupportedOperationWarning(Res.GetString(Res.CodeGenSupportReturnTypeAttributes, ServiceImporter.CodeGenerator.GetType().Name));
826                     return null;
827                 }
828             }
829
830             string resultsName = localIdentifiers.MakeUnique("results");
831
832             if (Style == ServiceDescriptionImportStyle.Client) {
833                 bool oldAsync = (ServiceImporter.CodeGenerationOptions & CodeGenerationOptions.GenerateOldAsync) != 0;
834                 bool newAsync = (ServiceImporter.CodeGenerationOptions & CodeGenerationOptions.GenerateNewAsync) != 0 && 
835                     ServiceImporter.CodeGenerator.Supports(GeneratorSupport.DeclareEvents) && 
836                     ServiceImporter.CodeGenerator.Supports(GeneratorSupport.DeclareDelegates);
837                 CodeExpression[] invokeParams = new CodeExpression[2];
838                 CreateInvokeParams(invokeParams, uniqueMethodName, parameters.InParameters, parameters.InCheckSpecifiedCount);
839                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Invoke", invokeParams);
840                 WriteReturnMappings(mainCodeMethod, invoke, parameters, resultsName);
841
842                 if (oldAsync) {
843                     int inCount = parameters.InParameters.Count + parameters.InCheckSpecifiedCount;
844
845                     string[] asyncParameterTypes = new string[inCount + 2];
846                     SoapParameter.GetTypeFullNames(parameters.InParameters, asyncParameterTypes, 0, parameters.InCheckSpecifiedCount, ServiceImporter.CodeGenerator);
847                     asyncParameterTypes[inCount] = typeof(AsyncCallback).FullName;
848                     asyncParameterTypes[inCount + 1] = typeof(object).FullName;
849
850                     string[] asyncParameterNames = new string[inCount + 2];
851                     SoapParameter.GetNames(parameters.InParameters, asyncParameterNames, 0, parameters.InCheckSpecifiedCount);
852                     asyncParameterNames[inCount] = "callback";
853                     asyncParameterNames[inCount + 1] = "asyncState";
854
855                     CodeFlags[] asyncParameterFlags = new CodeFlags[inCount + 2];
856
857                     CodeMemberMethod beginCodeMethod = WebCodeGenerator.AddMethod(this.CodeTypeDeclaration, "Begin" + uniqueMethodName, 
858                         asyncParameterFlags,
859                         asyncParameterTypes, 
860                         asyncParameterNames, 
861                         typeof(IAsyncResult).FullName, 
862                         null, 
863                         CodeFlags.IsPublic);
864
865                     beginCodeMethod.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true));
866
867                     invokeParams = new CodeExpression[4];
868                     CreateInvokeParams(invokeParams, uniqueMethodName, parameters.InParameters, parameters.InCheckSpecifiedCount);
869                     invokeParams[2] = new CodeArgumentReferenceExpression("callback");
870                     invokeParams[3] = new CodeArgumentReferenceExpression("asyncState");
871
872                     invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "BeginInvoke", invokeParams);
873                     beginCodeMethod.Statements.Add(new CodeMethodReturnStatement(invoke));
874
875                     int outCount = parameters.OutParameters.Count + parameters.OutCheckSpecifiedCount;
876                     string[] asyncReturnTypes = new string[outCount + 1];
877                     SoapParameter.GetTypeFullNames(parameters.OutParameters, asyncReturnTypes, 1, parameters.OutCheckSpecifiedCount, ServiceImporter.CodeGenerator);
878                     asyncReturnTypes[0] = typeof(IAsyncResult).FullName;
879
880                     string[] asyncReturnNames = new string[outCount + 1];
881                     SoapParameter.GetNames(parameters.OutParameters, asyncReturnNames, 1, parameters.OutCheckSpecifiedCount);
882                     asyncReturnNames[0] = "asyncResult";
883
884                     CodeFlags[] asyncReturnFlags = new CodeFlags[outCount + 1];
885                     for (int i = 0; i < outCount; i++)
886                         asyncReturnFlags[i + 1] = CodeFlags.IsOut;
887
888                     CodeMemberMethod codeMethod = WebCodeGenerator.AddMethod(this.CodeTypeDeclaration, "End" + uniqueMethodName, 
889                         asyncReturnFlags, 
890                         asyncReturnTypes, 
891                         asyncReturnNames, 
892                         parameters.Return == null ? typeof(void).FullName : WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator), 
893                         null, 
894                         CodeFlags.IsPublic);
895
896                     codeMethod.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true));
897
898                     CodeExpression invokeParam = new CodeArgumentReferenceExpression("asyncResult");
899                     invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "EndInvoke", new CodeExpression[] { invokeParam });
900
901                     WriteReturnMappings(codeMethod, invoke, parameters, resultsName);
902                 }
903
904                 // new RAD Async pattern
905                 if (newAsync) {
906                     string methodKey = MethodSignature(uniqueMethodName, returnType, parameterFlags, parameterTypes);
907                     DelegateInfo delegateInfo = (DelegateInfo)ExportContext[methodKey];
908                     if (delegateInfo == null) {
909                         string handlerType = ClassNames.AddUnique(uniqueMethodName + "CompletedEventHandler", uniqueMethodName);
910                         string handlerArgs = ClassNames.AddUnique(uniqueMethodName + "CompletedEventArgs", uniqueMethodName);
911                         delegateInfo = new DelegateInfo(handlerType, handlerArgs);
912                     }
913                     string handlerName = MethodNames.AddUnique(uniqueMethodName + "Completed", uniqueMethodName);
914                     string asyncName = MethodNames.AddUnique(uniqueMethodName + "Async", uniqueMethodName);
915                     string callbackMember = MethodNames.AddUnique(uniqueMethodName + "OperationCompleted", uniqueMethodName);
916                     string callbackName = MethodNames.AddUnique("On" + uniqueMethodName + "OperationCompleted", uniqueMethodName);
917
918                     // public event xxxCompletedEventHandler xxxCompleted;
919                     WebCodeGenerator.AddEvent(this.CodeTypeDeclaration.Members, delegateInfo.handlerType, handlerName);
920
921                     // private SendOrPostCallback xxxOperationCompleted;
922                     WebCodeGenerator.AddCallbackDeclaration(this.CodeTypeDeclaration.Members, callbackMember);
923
924                     // create the pair of xxxAsync methods
925                     string[] inParamNames = SoapParameter.GetNames(parameters.InParameters, parameters.InCheckSpecifiedCount);
926                     string userState = UniqueName("userState", inParamNames);
927                     CodeMemberMethod asyncCodeMethod = WebCodeGenerator.AddAsyncMethod(this.CodeTypeDeclaration, asyncName, 
928                         SoapParameter.GetTypeFullNames(parameters.InParameters, parameters.InCheckSpecifiedCount, ServiceImporter.CodeGenerator), inParamNames, callbackMember, callbackName, userState);
929
930                     // Generate InvokeAsync call
931                     invokeParams = new CodeExpression[4];
932                     CreateInvokeParams(invokeParams, uniqueMethodName, parameters.InParameters, parameters.InCheckSpecifiedCount);
933                     invokeParams[2] = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), callbackMember);
934                     invokeParams[3] = new CodeArgumentReferenceExpression(userState);
935                         
936                     invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "InvokeAsync", invokeParams);
937                     asyncCodeMethod.Statements.Add(invoke);
938
939                     //  private void On_xxx_OperationCompleted(object arg) {..}
940                     bool methodHasOutParameters = parameters.Return != null || parameters.OutParameters.Count > 0;
941                     WebCodeGenerator.AddCallbackImplementation(this.CodeTypeDeclaration, callbackName, handlerName, delegateInfo.handlerArgs, methodHasOutParameters);
942
943                     if (ExportContext[methodKey] == null) {
944                         // public delegate void xxxCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs args);
945                         WebCodeGenerator.AddDelegate(ExtraCodeClasses, delegateInfo.handlerType, methodHasOutParameters ? delegateInfo.handlerArgs : typeof(AsyncCompletedEventArgs).FullName);
946                         
947                         // Create strongly-typed Args class
948                         if (methodHasOutParameters) {
949                             int outCount = parameters.OutParameters.Count + parameters.OutCheckSpecifiedCount;
950                             string[] asyncReturnTypes = new string[outCount + 1];
951                             SoapParameter.GetTypeFullNames(parameters.OutParameters, asyncReturnTypes, 1, parameters.OutCheckSpecifiedCount, ServiceImporter.CodeGenerator);
952                             asyncReturnTypes[0] = parameters.Return == null ? null : WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator);
953
954                             string[] asyncReturnNames = new string[outCount + 1];
955                             SoapParameter.GetNames(parameters.OutParameters, asyncReturnNames, 1, parameters.OutCheckSpecifiedCount);
956                             asyncReturnNames[0] = parameters.Return == null ? null : "Result";
957                             ExtraCodeClasses.Add(WebCodeGenerator.CreateArgsClass(delegateInfo.handlerArgs, asyncReturnTypes, asyncReturnNames, ServiceImporter.CodeGenerator.Supports(GeneratorSupport.PartialTypes)));
958                         }
959                         ExportContext[methodKey] = delegateInfo;
960                     }
961                 }
962             }
963             return mainCodeMethod;
964         }
965
966         void WriteReturnMappings(CodeMemberMethod codeMethod, CodeExpression invoke, SoapParameters parameters, string resultsName) {
967             if (parameters.Return == null && parameters.OutParameters.Count == 0) {
968                 codeMethod.Statements.Add(new CodeExpressionStatement(invoke));
969             }
970             else {
971                 codeMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(object[]), resultsName, invoke));
972
973                 int count = parameters.Return == null ? 0 : 1;
974                 for (int i = 0; i < parameters.OutParameters.Count; i++) {
975                     SoapParameter parameter = (SoapParameter)parameters.OutParameters[i];
976                     CodeExpression target = new CodeArgumentReferenceExpression(parameter.name);
977                     CodeExpression value = new CodeArrayIndexerExpression();
978                     ((CodeArrayIndexerExpression)value).TargetObject = new CodeVariableReferenceExpression(resultsName);
979                     ((CodeArrayIndexerExpression)value).Indices.Add(new CodePrimitiveExpression(count++));
980                     value = new CodeCastExpression(WebCodeGenerator.FullTypeName(parameter.mapping, ServiceImporter.CodeGenerator), value);
981                     codeMethod.Statements.Add(new CodeAssignStatement(target, value));
982                     if (parameter.mapping.CheckSpecified) {
983                         target = new CodeArgumentReferenceExpression(parameter.name + "Specified");
984                         value = new CodeArrayIndexerExpression();
985                         ((CodeArrayIndexerExpression) value).TargetObject = new CodeVariableReferenceExpression(resultsName);
986                         ((CodeArrayIndexerExpression)value).Indices.Add(new CodePrimitiveExpression(count++));
987                         value = new CodeCastExpression(typeof(bool).FullName, value);
988                         codeMethod.Statements.Add(new CodeAssignStatement(target, value));
989                     }
990                 }
991
992                 if (parameters.Return != null) {
993                     CodeExpression value = new CodeArrayIndexerExpression();
994                     ((CodeArrayIndexerExpression)value).TargetObject = new CodeVariableReferenceExpression(resultsName);
995                     ((CodeArrayIndexerExpression)value).Indices.Add(new CodePrimitiveExpression(0));
996                     value = new CodeCastExpression(WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator), value);
997                     codeMethod.Statements.Add(new CodeMethodReturnStatement(value));
998                 }
999             }
1000         }
1001
1002         void CreateInvokeParams(CodeExpression[] invokeParams, string methodName, IList parameters, int checkSpecifiedCount) {
1003             invokeParams[0] = new CodePrimitiveExpression(methodName);
1004
1005             CodeExpression[] values = new CodeExpression[parameters.Count + checkSpecifiedCount];
1006             int value = 0;
1007             for (int i = 0; i < parameters.Count; i++) {
1008                 SoapParameter parameter = (SoapParameter)parameters[i];
1009                 values[value++] = new CodeArgumentReferenceExpression(parameter.name);
1010                 if (parameter.mapping.CheckSpecified)
1011                     values[value++] = new CodeArgumentReferenceExpression(parameter.specifiedName);
1012             }
1013             invokeParams[1] = new CodeArrayCreateExpression(typeof(object).FullName, values);
1014         }
1015
1016         // returns false if we didn't like the message -- otherwise caller is safe to use body binding and binding style
1017         bool CheckMessageStyles(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, out bool hasWrapper) {
1018             hasWrapper = false;
1019             if (soapBodyBinding.Use == SoapBindingUse.Default) {
1020                 soapBodyBinding.Use = SoapBindingUse.Literal;
1021             }
1022             if (soapBodyBinding.Use == SoapBindingUse.Literal) {
1023                 if (soapBindingStyle == SoapBindingStyle.Rpc) {
1024                     foreach (MessagePart part in parts) {
1025                         if (!part.Element.IsEmpty) {
1026                             UnsupportedOperationBindingWarning(Res.GetString(Res.EachMessagePartInRpcUseLiteralMessageMustSpecify0));
1027                             return false;
1028                         }
1029                     }
1030                     return true;
1031                 }
1032                 if (parts.Length == 1 && !parts[0].Type.IsEmpty) {
1033                     // special top-level any case
1034                     if (!parts[0].Element.IsEmpty) {
1035                         UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingATypeForUseLiteralMessagesIs0));
1036                         return false;
1037                     }
1038                     XmlMembersMapping membersMapping = xmlImporter.ImportAnyType(parts[0].Type, parts[0].Name);
1039                     if (membersMapping == null) {
1040                         UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingATypeForUseLiteralMessagesIsAny, parts[0].Type.Name, parts[0].Type.Namespace));
1041                         return false;
1042                     }
1043                     return true;
1044                 }
1045                 else {
1046                     foreach (MessagePart part in parts) {
1047                         if (!part.Type.IsEmpty) {
1048                             UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingATypeForUseLiteralMessagesIs0));
1049                             return false;
1050                         }
1051                         if (part.Element.IsEmpty) {
1052                             UnsupportedOperationBindingWarning(Res.GetString(Res.EachMessagePartInAUseLiteralMessageMustSpecify0));
1053                             return false;
1054                         }
1055                     }
1056                 }
1057             }
1058             else if (soapBodyBinding.Use == SoapBindingUse.Encoded) {
1059                 if (!IsSoapEncodingPresent(soapBodyBinding.Encoding)) {
1060                     UnsupportedOperationBindingWarning(Res.GetString(Res.TheEncodingIsNotSupported1, soapBodyBinding.Encoding));
1061                     return false;
1062                 }
1063                 foreach (MessagePart part in parts) {
1064                     if (!part.Element.IsEmpty) {
1065                         UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingAnElementForUseEncodedMessageParts0));
1066                         return false;
1067                     }
1068                     if (part.Type.IsEmpty) {
1069                         UnsupportedOperationBindingWarning(Res.GetString(Res.EachMessagePartInAnUseEncodedMessageMustSpecify0));
1070                         return false;
1071                     }
1072                 }
1073             }
1074
1075             if (soapBindingStyle == SoapBindingStyle.Rpc) {
1076                 return true;
1077             }
1078             else if (soapBindingStyle == SoapBindingStyle.Document) {
1079                 // NOTE, Microsoft.  WSDL doesn't really let us figure out whether a document is
1080                 // in fact a struct containing parameters, so we apply a little heuristic here
1081                 // in order to produce the appropriate programming model.
1082                 hasWrapper = (parts.Length == 1 && string.Compare(parts[0].Name, "parameters", StringComparison.Ordinal) == 0);
1083                 return true;
1084             }
1085             return false;
1086         }
1087         
1088         /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.IsSoapEncodingPresent"]/*' />
1089         /// <internalonly/>
1090         protected virtual bool IsSoapEncodingPresent(string uriList) {
1091             int iStart = 0;
1092             do {
1093                 iStart = uriList.IndexOf(Soap.Encoding, iStart, StringComparison.Ordinal);
1094                 if (iStart < 0)
1095                     return false;
1096                 int iEnd = iStart + Soap.Encoding.Length;
1097                 if (iStart == 0 || uriList[iStart - 1] == ' ')
1098                     if (iEnd == uriList.Length || uriList[iEnd] == ' ')
1099                         return true;
1100                 iStart = iEnd;
1101             } while (iStart < uriList.Length);
1102             return false;
1103         }
1104
1105         MessagePart[] GetMessageParts(Message message, SoapBodyBinding soapBodyBinding) {
1106             MessagePart[] parts;
1107             if (soapBodyBinding.Parts == null) {
1108                 parts = new MessagePart[message.Parts.Count];
1109                 message.Parts.CopyTo(parts, 0);
1110             }
1111             else {
1112                 parts = message.FindPartsByName(soapBodyBinding.Parts);
1113             }
1114             return parts;
1115         }
1116
1117         XmlMembersMapping ImportMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, bool wrapped) {
1118             if (soapBodyBinding.Use == SoapBindingUse.Encoded)
1119                 return ImportEncodedMessage(messageName, parts, soapBodyBinding, wrapped);
1120             else
1121                 return ImportLiteralMessage(messageName, parts, soapBodyBinding, soapBindingStyle, wrapped);
1122         }
1123
1124         XmlMembersMapping ImportEncodedMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, bool wrapped) {
1125             XmlMembersMapping membersMapping;
1126             if (wrapped) {
1127                 SoapSchemaMember schemaMember = new SoapSchemaMember();
1128                 schemaMember.MemberName = parts[0].Name;
1129                 schemaMember.MemberType = parts[0].Type;
1130                 membersMapping = soapImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, schemaMember);
1131             }
1132             else {
1133                 SoapSchemaMember[] schemaMembers = new SoapSchemaMember[parts.Length];
1134                 for (int i = 0; i < schemaMembers.Length; i++) {
1135                     MessagePart part = parts[i];
1136                     SoapSchemaMember schemaMember = new SoapSchemaMember();
1137                     schemaMember.MemberName = part.Name;
1138                     schemaMember.MemberType = part.Type;
1139                     schemaMembers[i] = schemaMember;
1140                 }
1141                 membersMapping = soapImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, schemaMembers);
1142             } 
1143             soapMembers.Add(membersMapping);
1144             return membersMapping;
1145         }
1146
1147         XmlMembersMapping ImportLiteralMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, bool wrapped) {
1148             XmlMembersMapping membersMapping;
1149             if (soapBindingStyle == SoapBindingStyle.Rpc) {
1150                 SoapSchemaMember[] schemaMembers = new SoapSchemaMember[parts.Length];
1151                 for (int i = 0; i < schemaMembers.Length; i++) {
1152                     MessagePart part = parts[i];
1153                     SoapSchemaMember schemaMember = new SoapSchemaMember();
1154                     schemaMember.MemberName = part.Name;
1155                     schemaMember.MemberType = part.Type;
1156                     schemaMembers[i] = schemaMember;
1157                 }
1158                 membersMapping = xmlImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, schemaMembers);
1159             }
1160             else if (wrapped) {
1161                 membersMapping = xmlImporter.ImportMembersMapping(parts[0].Element);
1162             }
1163             else {
1164                 if (parts.Length == 1 && !parts[0].Type.IsEmpty) {
1165                     // special case for <any> at root
1166                     // we know this will work because we tried it earlier in CheckMessageStyles.
1167                     membersMapping = xmlImporter.ImportAnyType(parts[0].Type, parts[0].Name);
1168                     xmlMembers.Add(membersMapping);
1169                     return membersMapping;
1170                 }
1171                 XmlQualifiedName[] names = new XmlQualifiedName[parts.Length];
1172                 for (int i = 0; i < parts.Length; i++)
1173                     names[i] = parts[i].Element;
1174                 membersMapping = xmlImporter.ImportMembersMapping(names);
1175             }
1176             xmlMembers.Add(membersMapping);
1177             return membersMapping;
1178         }
1179     }
1180 }