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