2005-10-05 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / SoapProtocolImporter.cs
1 // 
2 // System.Web.Services.Description.SoapProtocolImporter.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Tim Coleman, 2002
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 System.CodeDom;
33 using System.Web.Services;
34 using System.Web.Services.Protocols;
35 using System.Web.Services.Configuration;
36 using System.Xml;
37 using System.Xml.Schema;
38 using System.Xml.Serialization;
39 using System.Configuration;
40 using System.Collections;
41
42 namespace System.Web.Services.Description {
43         public class SoapProtocolImporter : ProtocolImporter {
44
45                 #region Fields
46
47                 SoapBinding soapBinding;
48                 SoapCodeExporter soapExporter;
49                 SoapSchemaImporter soapImporter;
50                 XmlCodeExporter xmlExporter;
51                 XmlSchemaImporter xmlImporter;
52                 CodeIdentifiers memberIds;
53                 ArrayList extensionImporters;
54                 Hashtable headerVariables;
55                 XmlSchemas xmlSchemas;
56                 XmlSchemas soapSchemas;
57                 
58                 #endregion // Fields
59
60                 #region Constructors
61
62                 public SoapProtocolImporter ()
63                 {
64                         extensionImporters = ExtensionManager.BuildExtensionImporters ();
65                 }
66                 
67                 void SetBinding (SoapBinding soapBinding)
68                 {
69                         this.soapBinding = soapBinding;
70                 }
71                 
72                 #endregion // Constructors
73
74                 #region Properties
75
76                 public override string ProtocolName {
77                         get { return "Soap"; }
78                 }
79
80                 public SoapBinding SoapBinding {
81                         get { return soapBinding; }
82                 }
83
84                 public SoapCodeExporter SoapExporter {
85                         get { return soapExporter; }
86                 }
87
88                 public SoapSchemaImporter SoapImporter {
89                         get { return soapImporter; }
90                 }
91
92                 public XmlCodeExporter XmlExporter {
93                         get { return xmlExporter; }
94                 }
95
96                 public XmlSchemaImporter XmlImporter {
97                         get { return xmlImporter; }
98                 }
99
100                 #endregion // Properties
101
102                 #region Methods
103
104                 protected override CodeTypeDeclaration BeginClass ()
105                 {
106                         soapBinding = (SoapBinding) Binding.Extensions.Find (typeof(SoapBinding));
107                         
108                         CodeTypeDeclaration codeClass = new CodeTypeDeclaration (ClassName);
109                         
110                         string location = null;
111                         
112                         if (Port != null) {
113                                 SoapAddressBinding sab = (SoapAddressBinding) Port.Extensions.Find (typeof(SoapAddressBinding));
114                                 if (sab != null) location = sab.Location;
115                         }
116                         
117                         string namspace = (Port != null ? Port.Binding.Namespace : Binding.ServiceDescription.TargetNamespace);
118                         string name = (Port != null ? Port.Name : Binding.Name);
119
120                         if (Style == ServiceDescriptionImportStyle.Client) {
121                                 CodeTypeReference ctr = new CodeTypeReference ("System.Web.Services.Protocols.SoapHttpClientProtocol");
122                                 codeClass.BaseTypes.Add (ctr);
123                         }
124                         else {
125                                 CodeTypeReference ctr = new CodeTypeReference ("System.Web.Services.WebService");
126                                 codeClass.BaseTypes.Add (ctr);
127                                 CodeAttributeDeclaration attws = new CodeAttributeDeclaration ("System.Web.Services.WebServiceAttribute");
128                                 attws.Arguments.Add (GetArg ("Namespace", namspace));
129                                 AddCustomAttribute (codeClass, attws, true);
130                         }
131                         
132                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.WebServiceBinding");
133                         att.Arguments.Add (GetArg ("Name", name));
134                         att.Arguments.Add (GetArg ("Namespace", namspace));
135                         AddCustomAttribute (codeClass, att, true);
136         
137                         if (Style == ServiceDescriptionImportStyle.Client) {
138                                 CodeConstructor cc = new CodeConstructor ();
139                                 cc.Attributes = MemberAttributes.Public;
140                                 GenerateServiceUrl (location, cc.Statements);
141                                 codeClass.Members.Add (cc);
142                         }
143                         
144                         memberIds = new CodeIdentifiers ();
145                         headerVariables = new Hashtable ();
146                         return codeClass;
147                 }
148                 
149                 protected override void BeginNamespace ()
150                 {
151 #if NET_2_0
152                         xmlImporter = new XmlSchemaImporter (LiteralSchemas, base.CodeGenerationOptions, base.CodeGenerator, base.ImportContext);
153                         soapImporter = new SoapSchemaImporter (EncodedSchemas, base.CodeGenerationOptions, base.CodeGenerator, base.ImportContext);
154                         xmlExporter = new XmlCodeExporter (CodeNamespace, null, base.CodeGenerator, base.CodeGenerationOptions, null);
155                         soapExporter = new SoapCodeExporter (CodeNamespace, null, base.CodeGenerator, base.CodeGenerationOptions, null);
156 #else
157                         xmlImporter = new XmlSchemaImporter (LiteralSchemas, ClassNames);
158                         soapImporter = new SoapSchemaImporter (EncodedSchemas, ClassNames);
159                         xmlExporter = new XmlCodeExporter (CodeNamespace, null);
160                         soapExporter = new SoapCodeExporter (CodeNamespace, null);
161 #endif
162                 }
163
164                 protected override void EndClass ()
165                 {
166                         SoapTransportImporter transportImporter = SoapTransportImporter.FindTransportImporter (soapBinding.Transport);
167                         if (transportImporter == null) throw new InvalidOperationException ("Transport '" + soapBinding.Transport + "' not supported");
168                         transportImporter.ImportContext = this;
169                         transportImporter.ImportClass ();
170                         
171                         if (xmlExporter.IncludeMetadata.Count > 0 || soapExporter.IncludeMetadata.Count > 0)
172                         {
173                                 if (CodeTypeDeclaration.CustomAttributes == null)
174                                         CodeTypeDeclaration.CustomAttributes = new CodeAttributeDeclarationCollection ();
175                                 CodeTypeDeclaration.CustomAttributes.AddRange (xmlExporter.IncludeMetadata);
176                                 CodeTypeDeclaration.CustomAttributes.AddRange (soapExporter.IncludeMetadata);
177                         }
178                 }
179
180                 protected override void EndNamespace ()
181                 {
182                 }
183
184                 protected override bool IsBindingSupported ()
185                 {
186                         return Binding.Extensions.Find (typeof(SoapBinding)) != null;
187                 }
188
189                 [MonoTODO]
190                 protected override bool IsOperationFlowSupported (OperationFlow flow)
191                 {
192                         throw new NotImplementedException ();
193                 }
194
195                 [MonoTODO]
196                 protected virtual bool IsSoapEncodingPresent (string uriList)
197                 {
198                         throw new NotImplementedException ();
199                 }
200
201                 protected override CodeMemberMethod GenerateMethod ()
202                 {
203                         try
204                         {
205                                 SoapOperationBinding soapOper = OperationBinding.Extensions.Find (typeof (SoapOperationBinding)) as SoapOperationBinding;
206                                 if (soapOper == null) throw new InvalidOperationException ("Soap operation binding not found");
207
208                                 SoapBindingStyle style = soapOper.Style != SoapBindingStyle.Default ? soapOper.Style : soapBinding.Style;
209                         
210                                 SoapBodyBinding isbb = null;
211                                 XmlMembersMapping inputMembers = null;
212                                 
213                                 isbb = OperationBinding.Input.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
214                                 if (isbb == null) throw new InvalidOperationException ("Soap body binding not found");
215                         
216                                 inputMembers = ImportMembersMapping (InputMessage, isbb, style, false);
217                                 if (inputMembers == null) throw new InvalidOperationException ("Input message not declared");
218                                 
219                                 // If OperationBinding.Output is null, it is an OneWay operation
220                                 
221                                 SoapBodyBinding osbb = null;
222                                 XmlMembersMapping outputMembers = null;
223                                 
224                                 if (OperationBinding.Output != null) {
225                                         osbb = OperationBinding.Output.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
226                                         if (osbb == null) throw new InvalidOperationException ("Soap body binding not found");
227
228                                         outputMembers = ImportMembersMapping (OutputMessage, osbb, style, true);
229                                         if (outputMembers == null) throw new InvalidOperationException ("Output message not declared");
230                                 }
231                                 
232                                 CodeMemberMethod met = GenerateMethod (memberIds, soapOper, isbb, inputMembers, outputMembers);
233                                 
234                                 if (isbb.Use == SoapBindingUse.Literal)
235                                         xmlExporter.ExportMembersMapping (inputMembers);
236                                 else
237                                         soapExporter.ExportMembersMapping (inputMembers);
238                                 
239                                 if (osbb != null) {
240                                         if (osbb.Use == SoapBindingUse.Literal)
241                                                 xmlExporter.ExportMembersMapping (outputMembers);
242                                         else
243                                                 soapExporter.ExportMembersMapping (outputMembers);
244                                 }
245                                 
246                                 foreach (SoapExtensionImporter eximporter in extensionImporters)
247                                 {
248                                         eximporter.ImportContext = this;
249                                         eximporter.ImportMethod (met.CustomAttributes);
250                                 }
251                                 
252                                 return met;
253                         }
254                         catch (InvalidOperationException ex)
255                         {
256                                 UnsupportedOperationBindingWarning (ex.Message);
257                                 return null;
258                         }
259                 }
260                 
261                 XmlMembersMapping ImportMembersMapping (Message msg, SoapBodyBinding sbb, SoapBindingStyle style, bool output)
262                 {
263                         string elemName = Operation.Name;
264                         if (output) elemName += "Response";
265
266                         if (msg.Parts.Count == 1 && msg.Parts[0].Name == "parameters")
267                         {
268                                 // Wrapped parameter style
269                                 
270                                 MessagePart part = msg.Parts[0];
271                                 if (sbb.Use == SoapBindingUse.Encoded)
272                                 {
273                                         SoapSchemaMember ssm = new SoapSchemaMember ();
274                                         ssm.MemberName = part.Name;
275                                         ssm.MemberType = part.Type;
276                                         return soapImporter.ImportMembersMapping (elemName, part.Type.Namespace, ssm);
277                                 }
278                                 else
279                                         return xmlImporter.ImportMembersMapping (part.Element);
280                         }
281                         else
282                         {
283                                 if (sbb.Use == SoapBindingUse.Encoded)
284                                 {
285                                         SoapSchemaMember[] mems = new SoapSchemaMember [msg.Parts.Count];
286                                         for (int n=0; n<mems.Length; n++)
287                                         {
288                                                 SoapSchemaMember mem = new SoapSchemaMember();
289                                                 mem.MemberName = msg.Parts[n].Name;
290                                                 mem.MemberType = msg.Parts[n].Type;
291                                                 mems[n] = mem;
292                                         }
293                                         
294                                         // Rpc messages always have a wrapping element
295                                         if (style == SoapBindingStyle.Rpc)
296                                                 return soapImporter.ImportMembersMapping (elemName, sbb.Namespace, mems, true);
297                                         else
298                                                 return soapImporter.ImportMembersMapping ("", "", mems, false);
299                                 }
300                                 else
301                                 {
302                                         if (style == SoapBindingStyle.Rpc)
303                                                 throw new InvalidOperationException ("The combination of style=rpc with use=literal is not supported");
304                                         
305                                         if (msg.Parts.Count == 1 && msg.Parts[0].Type != XmlQualifiedName.Empty)
306                                                 return xmlImporter.ImportAnyType (msg.Parts[0].Type, null);
307                                         else
308                                         {
309                                                 XmlQualifiedName[] pnames = new XmlQualifiedName [msg.Parts.Count];
310                                                 for (int n=0; n<pnames.Length; n++)
311                                                         pnames[n] = msg.Parts[n].Element;
312                                                 return xmlImporter.ImportMembersMapping (pnames);
313                                         }
314                                 }
315                         }
316                 }
317                 
318                 CodeMemberMethod GenerateMethod (CodeIdentifiers memberIds, SoapOperationBinding soapOper, SoapBodyBinding bodyBinding, XmlMembersMapping inputMembers, XmlMembersMapping outputMembers)
319                 {
320                         CodeIdentifiers pids = new CodeIdentifiers ();
321                         CodeMemberMethod method = new CodeMemberMethod ();
322                         CodeMemberMethod methodBegin = new CodeMemberMethod ();
323                         CodeMemberMethod methodEnd = new CodeMemberMethod ();
324                         method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
325                         methodBegin.Attributes = MemberAttributes.Public | MemberAttributes.Final;
326                         methodEnd.Attributes = MemberAttributes.Public | MemberAttributes.Final;
327                         
328                         SoapBindingStyle style = soapOper.Style != SoapBindingStyle.Default ? soapOper.Style : soapBinding.Style;
329                         
330                         // Find unique names for temporary variables
331                         
332                         for (int n=0; n<inputMembers.Count; n++)
333                                 pids.AddUnique (inputMembers[n].MemberName, inputMembers[n]);
334
335                         if (outputMembers != null)
336                                 for (int n=0; n<outputMembers.Count; n++)
337                                         pids.AddUnique (outputMembers[n].MemberName, outputMembers[n]);
338                                 
339                         string varAsyncResult = pids.AddUnique ("asyncResult","asyncResult");
340                         string varResults = pids.AddUnique ("results","results");
341                         string varCallback = pids.AddUnique ("callback","callback");
342                         string varAsyncState = pids.AddUnique ("asyncState","asyncState");
343
344                         string messageName = memberIds.AddUnique(CodeIdentifier.MakeValid(Operation.Name),method);
345
346                         method.Name = CodeIdentifier.MakeValid(Operation.Name);
347                         if (method.Name == ClassName) method.Name += "1";
348                         methodBegin.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("Begin" + method.Name),method);
349                         methodEnd.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("End" + method.Name),method);
350
351                         method.ReturnType = new CodeTypeReference (typeof(void));
352                         methodEnd.ReturnType = new CodeTypeReference (typeof(void));
353                         methodEnd.Parameters.Add (new CodeParameterDeclarationExpression (typeof (IAsyncResult),varAsyncResult));
354
355                         CodeExpression[] paramArray = new CodeExpression [inputMembers.Count];
356                         CodeParameterDeclarationExpression[] outParams = new CodeParameterDeclarationExpression [outputMembers != null ? outputMembers.Count : 0];
357
358                         for (int n=0; n<inputMembers.Count; n++)
359                         {
360                                 CodeParameterDeclarationExpression param = GenerateParameter (inputMembers[n], FieldDirection.In);
361                                 method.Parameters.Add (param);
362                                 GenerateMemberAttributes (inputMembers, inputMembers[n], bodyBinding.Use, param);
363                                 methodBegin.Parameters.Add (GenerateParameter (inputMembers[n], FieldDirection.In));
364                                 paramArray [n] = new CodeVariableReferenceExpression (param.Name);
365                         }
366
367                         if (outputMembers != null)
368                         {
369                                 bool hasReturn = false;
370                                 for (int n=0; n<outputMembers.Count; n++)
371                                 {
372                                         CodeParameterDeclarationExpression cpd = GenerateParameter (outputMembers[n], FieldDirection.Out);
373                                         outParams [n] = cpd;
374                                         
375                                         bool found = false;
376                                         foreach (CodeParameterDeclarationExpression ip in method.Parameters)
377                                         {
378                                                 if (ip.Name == cpd.Name && ip.Type.BaseType == cpd.Type.BaseType) {
379                                                         ip.Direction = FieldDirection.Ref;
380                                                         methodEnd.Parameters.Add (GenerateParameter (outputMembers[n], FieldDirection.Out));
381                                                         found = true;
382                                                         break;
383                                                 }
384                                         }
385                                         
386                                         if (found) continue;
387         
388                                         if (!hasReturn) 
389                                         {
390                                                 hasReturn = true;
391                                                 method.ReturnType = cpd.Type;
392                                                 methodEnd.ReturnType = cpd.Type;
393                                                 GenerateReturnAttributes (outputMembers, outputMembers[n], bodyBinding.Use, method);
394                                                 outParams [n] = null;
395                                                 continue;
396                                         }
397                                         
398                                         method.Parameters.Add (cpd);
399                                         GenerateMemberAttributes (outputMembers, outputMembers[n], bodyBinding.Use, cpd);
400                                         methodEnd.Parameters.Add (GenerateParameter (outputMembers[n], FieldDirection.Out));
401                                 }
402                         }
403                         
404                         methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (AsyncCallback),varCallback));
405                         methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object),varAsyncState));
406                         methodBegin.ReturnType = new CodeTypeReference (typeof(IAsyncResult));
407
408                         // Array of input parameters
409                         
410                         CodeArrayCreateExpression methodParams;
411                         if (paramArray.Length > 0)
412                                 methodParams = new CodeArrayCreateExpression (typeof(object), paramArray);
413                         else
414                                 methodParams = new CodeArrayCreateExpression (typeof(object), 0);
415
416                         // Assignment of output parameters
417                         
418                         CodeStatementCollection outAssign = new CodeStatementCollection ();
419                         CodeVariableReferenceExpression arrVar = new CodeVariableReferenceExpression (varResults);
420                         for (int n=0; n<outParams.Length; n++)
421                         {
422                                 CodeExpression index = new CodePrimitiveExpression (n);
423                                 if (outParams[n] == null)
424                                 {
425                                         CodeExpression res = new CodeCastExpression (method.ReturnType, new CodeArrayIndexerExpression (arrVar, index));
426                                         outAssign.Add (new CodeMethodReturnStatement (res));
427                                 }
428                                 else
429                                 {
430                                         CodeExpression res = new CodeCastExpression (outParams[n].Type, new CodeArrayIndexerExpression (arrVar, index));
431                                         CodeExpression var = new CodeVariableReferenceExpression (outParams[n].Name);
432                                         outAssign.Insert (0, new CodeAssignStatement (var, res));
433                                 }
434                         }
435                         
436                         if (Style == ServiceDescriptionImportStyle.Client) 
437                         {
438                                 // Invoke call
439                                 
440                                 CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
441                                 CodePrimitiveExpression varMsgName = new CodePrimitiveExpression (messageName);
442                                 CodeMethodInvokeExpression inv;
443                                 CodeVariableDeclarationStatement dec;
444         
445                                 inv = new CodeMethodInvokeExpression (ethis, "Invoke", varMsgName, methodParams);
446                                 if (outputMembers != null && outputMembers.Count > 0)
447                                 {
448                                         dec = new CodeVariableDeclarationStatement (typeof(object[]), varResults, inv);
449                                         method.Statements.Add (dec);
450                                         method.Statements.AddRange (outAssign);
451                                 }
452                                 else
453                                         method.Statements.Add (inv);
454                                 
455                                 // Begin Invoke Call
456                                 
457                                 CodeExpression expCallb = new CodeVariableReferenceExpression (varCallback);
458                                 CodeExpression expAsyncs = new CodeVariableReferenceExpression (varAsyncState);
459                                 inv = new CodeMethodInvokeExpression (ethis, "BeginInvoke", varMsgName, methodParams, expCallb, expAsyncs);
460                                 methodBegin.Statements.Add (new CodeMethodReturnStatement (inv));
461                                 
462                                 // End Invoke call
463                                 
464                                 CodeExpression varAsyncr = new CodeVariableReferenceExpression (varAsyncResult);
465                                 inv = new CodeMethodInvokeExpression (ethis, "EndInvoke", varAsyncr);
466                                 if (outputMembers != null && outputMembers.Count > 0)
467                                 {
468                                         dec = new CodeVariableDeclarationStatement (typeof(object[]), varResults, inv);
469                                         methodEnd.Statements.Add (dec);
470                                         methodEnd.Statements.AddRange (outAssign);
471                                 }
472                                 else
473                                         methodEnd.Statements.Add (inv);
474                         }
475                         else {
476                                 method.Attributes = MemberAttributes.Public | MemberAttributes.Abstract;
477                         }
478                         
479                         // Attributes
480                         
481                         ImportHeaders (method);
482                         
483                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.WebMethodAttribute");
484                         if (messageName != method.Name) att.Arguments.Add (GetArg ("MessageName",messageName));
485                         AddCustomAttribute (method, att, (Style == ServiceDescriptionImportStyle.Server));
486                         
487                         if (style == SoapBindingStyle.Rpc)
488                         {
489                                 att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.SoapRpcMethodAttribute");
490                                 att.Arguments.Add (GetArg (soapOper.SoapAction));
491                                 if (inputMembers.ElementName != method.Name) att.Arguments.Add (GetArg ("RequestElementName", inputMembers.ElementName));
492                                 if (outputMembers != null && outputMembers.ElementName != (method.Name + "Response")) att.Arguments.Add (GetArg ("ResponseElementName", outputMembers.ElementName));
493                                 att.Arguments.Add (GetArg ("RequestNamespace", inputMembers.Namespace));
494                                 if (outputMembers != null) att.Arguments.Add (GetArg ("ResponseNamespace", outputMembers.Namespace));
495                                 if (outputMembers == null) att.Arguments.Add (GetArg ("OneWay", true));
496                         }
497                         else
498                         {
499                                 if (outputMembers != null && (inputMembers.ElementName == "" && outputMembers.ElementName != "" || 
500                                         inputMembers.ElementName != "" && outputMembers.ElementName == ""))
501                                         throw new InvalidOperationException ("Parameter style is not the same for the input message and output message");
502         
503                                 att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.SoapDocumentMethodAttribute");
504                                 att.Arguments.Add (GetArg (soapOper.SoapAction));
505                                 if (inputMembers.ElementName != "") {
506                                         if (inputMembers.ElementName != method.Name) att.Arguments.Add (GetArg ("RequestElementName", inputMembers.ElementName));
507                                         if (outputMembers != null && outputMembers.ElementName != (method.Name + "Response")) att.Arguments.Add (GetArg ("ResponseElementName", outputMembers.ElementName));
508                                         att.Arguments.Add (GetArg ("RequestNamespace", inputMembers.Namespace));
509                                         if (outputMembers != null) att.Arguments.Add (GetArg ("ResponseNamespace", outputMembers.Namespace));
510                                         att.Arguments.Add (GetEnumArg ("ParameterStyle", "System.Web.Services.Protocols.SoapParameterStyle", "Wrapped"));
511                                 }
512                                 else
513                                         att.Arguments.Add (GetEnumArg ("ParameterStyle", "System.Web.Services.Protocols.SoapParameterStyle", "Bare"));
514                                         
515                                 if (outputMembers == null) att.Arguments.Add (GetArg ("OneWay", true));
516                                         
517                                 att.Arguments.Add (GetEnumArg ("Use", "System.Web.Services.Description.SoapBindingUse", bodyBinding.Use.ToString()));
518                         }
519                         
520                         AddCustomAttribute (method, att, true);
521                         
522                         CodeTypeDeclaration.Members.Add (method);
523                         
524                         if (Style == ServiceDescriptionImportStyle.Client) {
525                                 CodeTypeDeclaration.Members.Add (methodBegin);
526                                 CodeTypeDeclaration.Members.Add (methodEnd);
527                         }
528                         
529                         return method;
530                 }
531                 
532                 CodeParameterDeclarationExpression GenerateParameter (XmlMemberMapping member, FieldDirection dir)
533                 {
534                         CodeParameterDeclarationExpression par = new CodeParameterDeclarationExpression (member.TypeFullName, member.MemberName);
535                         par.Direction = dir;
536                         return par;
537                 }
538                 
539                 void GenerateMemberAttributes (XmlMembersMapping members, XmlMemberMapping member, SoapBindingUse use, CodeParameterDeclarationExpression param)
540                 {
541                         if (use == SoapBindingUse.Literal)
542                                 xmlExporter.AddMappingMetadata (param.CustomAttributes, member, members.Namespace);
543                         else
544                                 soapExporter.AddMappingMetadata (param.CustomAttributes, member);
545                 }
546                 
547                 void GenerateReturnAttributes (XmlMembersMapping members, XmlMemberMapping member, SoapBindingUse use, CodeMemberMethod method)
548                 {
549                         if (use == SoapBindingUse.Literal)
550                                 xmlExporter.AddMappingMetadata (method.ReturnTypeCustomAttributes, member, members.Namespace, (member.ElementName != method.Name + "Result"));
551                         else
552                                 soapExporter.AddMappingMetadata (method.ReturnTypeCustomAttributes, member, (member.ElementName != method.Name + "Result"));
553                 }
554                 
555                 void ImportHeaders (CodeMemberMethod method)
556                 {
557                         foreach (object ob in OperationBinding.Input.Extensions)
558                         {
559                                 SoapHeaderBinding hb = ob as SoapHeaderBinding;
560                                 if (hb == null) continue;
561                                 if (HasHeader (OperationBinding.Output, hb)) 
562                                         ImportHeader (method, hb, SoapHeaderDirection.In | SoapHeaderDirection.Out);
563                                 else
564                                         ImportHeader (method, hb, SoapHeaderDirection.In);
565                         }
566                         
567                         if (OperationBinding.Output == null) return;
568                         
569                         foreach (object ob in OperationBinding.Output.Extensions)
570                         {
571                                 SoapHeaderBinding hb = ob as SoapHeaderBinding;
572                                 if (hb == null) continue;
573                                 if (!HasHeader (OperationBinding.Input, hb)) 
574                                         ImportHeader (method, hb, SoapHeaderDirection.Out);
575                         }
576                 }
577                 
578                 bool HasHeader (MessageBinding msg, SoapHeaderBinding hb)
579                 {
580                         if (msg == null) return false;
581                         
582                         foreach (object ob in msg.Extensions) 
583                         {
584                                 SoapHeaderBinding mhb = ob as SoapHeaderBinding;
585                                 if ((mhb != null) && (mhb.Message == hb.Message) && (mhb.Part == hb.Part)) 
586                                         return true;
587                         }
588                         return false;
589                 }
590                 
591                 void ImportHeader (CodeMemberMethod method, SoapHeaderBinding hb, SoapHeaderDirection direction)
592                 {
593                         Message msg = ServiceDescriptions.GetMessage (hb.Message);
594                         if (msg == null) throw new InvalidOperationException ("Message " + hb.Message + " not found");
595                         MessagePart part = msg.Parts [hb.Part];
596                         if (part == null) throw new InvalidOperationException ("Message part " + hb.Part + " not found in message " + hb.Message);
597
598                         XmlTypeMapping map;
599                         if (hb.Use == SoapBindingUse.Literal)
600                         {
601                                 map = xmlImporter.ImportDerivedTypeMapping (part.Element, typeof (SoapHeader));
602                                 xmlExporter.ExportTypeMapping (map);
603                         }
604                         else
605                         {
606                                 map = soapImporter.ImportDerivedTypeMapping (part.Type, typeof (SoapHeader), true);
607                                 soapExporter.ExportTypeMapping (map);
608                         }
609
610                         bool required = false;
611
612                         string varName = headerVariables [map] as string;
613                         if (varName == null) 
614                         {
615                                 varName = memberIds.AddUnique(CodeIdentifier.MakeValid (map.TypeName + "Value"),hb);
616                                 headerVariables.Add (map, varName);
617                                 CodeMemberField codeField = new CodeMemberField (map.TypeFullName, varName);
618                                 codeField.Attributes = MemberAttributes.Public;
619                                 CodeTypeDeclaration.Members.Add (codeField);
620                         }
621                         
622                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.SoapHeaderAttribute");
623                         att.Arguments.Add (GetArg (varName));
624                         att.Arguments.Add (GetArg ("Required", required));
625                         if (direction != SoapHeaderDirection.In) att.Arguments.Add (GetEnumArg ("Direction", "System.Web.Services.Protocols.SoapHeaderDirection", direction.ToString ()));
626                         AddCustomAttribute (method, att, true);
627                 }
628                 
629                 #endregion
630         }
631 }