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