* BasicProfileChecker.cs: Some small fixes.
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / ProtocolImporter.cs
1 // 
2 // System.Web.Services.Description.ProtocolImporter.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;
33 using System.CodeDom;
34 using System.CodeDom.Compiler;
35 using System.Web.Services;
36 using System.Web.Services.Protocols;
37 using System.Xml.Serialization;
38 using System.Xml;
39 using System.Xml.Schema;
40 using System.Collections;
41 using System.Configuration;
42
43 namespace System.Web.Services.Description {
44         public abstract class ProtocolImporter {
45
46                 #region Fields
47
48                 Binding binding;
49                 string className;
50                 CodeIdentifiers classNames;
51                 CodeNamespace codeNamespace;
52                 CodeCompileUnit codeCompileUnit;
53                 CodeTypeDeclaration codeTypeDeclaration;
54                 Message inputMessage;
55                 string methodName;
56                 Operation operation;
57                 OperationBinding operationBinding;
58                 Message outputMessage;          
59                 Port port;
60                 PortType portType;
61                 string protocolName;
62                 Service service;
63                 ServiceDescriptionImportWarnings warnings = (ServiceDescriptionImportWarnings)0;        
64                 ServiceDescriptionImporter descriptionImporter;
65                 ImportInfo iinfo;
66                 XmlSchemas xmlSchemas;
67                 XmlSchemas soapSchemas;
68                 
69 #if NET_2_0
70                 ArrayList asyncTypes = new ArrayList ();
71 #endif
72
73                 #endregion // Fields
74
75                 #region Constructors
76         
77                 protected ProtocolImporter ()
78                 {
79                 }
80                 
81                 #endregion // Constructors
82
83                 #region Properties
84
85                 [MonoTODO]
86                 public XmlSchemas AbstractSchemas {
87                         get { return descriptionImporter.Schemas; }
88                 }
89
90                 public Binding Binding {
91                         get { return binding; }
92                 }
93
94                 public string ClassName {
95                         get { return className; }
96                 }
97
98                 public CodeIdentifiers ClassNames {
99                         get { return classNames; }
100                 }
101
102                 public CodeNamespace CodeNamespace {
103                         get { return codeNamespace; }
104                 }
105
106                 public CodeTypeDeclaration CodeTypeDeclaration {
107                         get { return codeTypeDeclaration; }
108                 }
109
110                 [MonoTODO]
111                 public XmlSchemas ConcreteSchemas {
112                         get { return descriptionImporter.Schemas; }
113                 }
114
115                 public Message InputMessage {
116                         get { return inputMessage; }
117                 }
118
119                 public string MethodName {
120                         get { return methodName; }
121                 }
122
123                 public Operation Operation {
124                         get { return operation; }
125                 }
126
127                 public OperationBinding OperationBinding {
128                         get { return operationBinding; }
129                 }
130
131                 public Message OutputMessage {
132                         get { return outputMessage; }
133                 }
134
135                 public Port Port {
136                         get { return port; }
137                 }
138
139                 public PortType PortType {
140                         get { return portType; }
141                 }
142
143                 public abstract string ProtocolName {
144                         get; 
145                 }
146
147                 public XmlSchemas Schemas {
148                         get { return descriptionImporter.Schemas; }
149                 }
150
151                 public Service Service {
152                         get { return service; } 
153                 }
154
155                 public ServiceDescriptionCollection ServiceDescriptions {
156                         get { return descriptionImporter.ServiceDescriptions; }
157                 }
158
159                 public ServiceDescriptionImportStyle Style {
160                         get { return descriptionImporter.Style; }
161                 }
162
163                 public ServiceDescriptionImportWarnings Warnings {
164                         get { return warnings; }
165                         set { warnings = value; }
166                 }
167                 
168                 internal ImportInfo ImportInfo
169                 {
170                         get { return iinfo; }
171                 }
172                 
173                 internal XmlSchemas LiteralSchemas
174                 {
175                         get { return xmlSchemas; }
176                 }
177                 
178                 internal XmlSchemas EncodedSchemas
179                 {
180                         get { return soapSchemas; }
181                 }
182                 
183 #if NET_2_0
184                 internal CodeGenerationOptions CodeGenerationOptions {
185                         get { return descriptionImporter.CodeGenerationOptions; }
186                 }
187                 
188                 internal ICodeGenerator CodeGenerator {
189                         get { return descriptionImporter.CodeGenerator; }
190                 }
191
192                 internal ImportContext ImportContext {
193                         get { return descriptionImporter.Context; }
194                 }
195 #endif
196
197                 #endregion // Properties
198
199                 #region Methods
200                 
201                 internal bool Import (ServiceDescriptionImporter descriptionImporter, CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, ArrayList importInfo)
202                 {
203                         this.descriptionImporter = descriptionImporter;
204                         this.classNames = new CodeIdentifiers();;
205                         this.codeNamespace = codeNamespace;
206                         this.codeCompileUnit = codeCompileUnit;
207
208                         warnings = (ServiceDescriptionImportWarnings) 0;
209                         
210                         bool found = false;
211                         
212                         ClasifySchemas (importInfo);
213
214                         BeginNamespace ();
215                         
216                         foreach (ImportInfo info in importInfo)
217                         {
218                                 foreach (Service service in info.ServiceDescription.Services)
219                                 {
220                                         this.service = service;
221                                         int bindingCount = 0;
222                                         foreach (Port port in service.Ports)
223                                         {
224                                                 binding = ServiceDescriptions.GetBinding (port.Binding);
225                                                 if (IsBindingSupported ()) bindingCount ++;
226                                         }
227                                         
228                                         foreach (Port port in service.Ports)
229                                         {
230                                                 this.iinfo = info;
231                                                 this.port = port;
232                                                 binding = ServiceDescriptions.GetBinding (port.Binding);
233                                                 if (!IsBindingSupported ()) continue;
234                                                 
235                                                 found = true;
236                                                 ImportPortBinding (bindingCount > 1);
237                                         }
238                                 }
239                         }
240                         
241                         if (!found)
242                         {
243                                 // Looks like MS.NET generates classes for all bindings if
244                                 // no services are present
245                                 
246                                 foreach (ImportInfo info in importInfo)
247                                 {
248                                         this.iinfo = info;
249                                         foreach (Binding b in info.ServiceDescription.Bindings)
250                                         {
251                                                 this.binding = b;
252                                                 this.service = null;
253                                                 this.port = null;
254                                                 if (!IsBindingSupported ()) continue;
255                                                 found = true;
256                                                 ImportPortBinding (true);
257                                         }
258                                 }
259                         }
260
261                         EndNamespace ();
262                         
263                         if (!found) warnings = ServiceDescriptionImportWarnings.NoCodeGenerated;
264                         return true;
265                 }
266
267                 void ImportPortBinding (bool multipleBindings)
268                 {
269                         if (port != null) {
270                                 if (multipleBindings) className = port.Name;
271                                 else className = service.Name;
272                         }
273                         else
274                                 className = binding.Name;
275                         
276                         className = classNames.AddUnique (CodeIdentifier.MakeValid (className), port);
277                         className = className.Replace ("_x0020_", "");  // MS.NET seems to do this
278                         
279                         try
280                         {
281                                 portType = ServiceDescriptions.GetPortType (binding.Type);
282                                 if (portType == null) throw new Exception ("Port type not found: " + binding.Type);
283
284                                 CodeTypeDeclaration codeClass = BeginClass ();
285                                 codeTypeDeclaration = codeClass;
286                                 if (port != null)
287                                         AddCodeType (codeClass, port.Documentation);
288                                 codeClass.Attributes = MemberAttributes.Public;
289                         
290                                 if (service != null && service.Documentation != null && service.Documentation != "")
291                                         AddComments (codeClass, service.Documentation);
292
293                                 if (Style == ServiceDescriptionImportStyle.Client) {
294                                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Diagnostics.DebuggerStepThroughAttribute");
295                                         AddCustomAttribute (codeClass, att, true);
296         
297                                         att = new CodeAttributeDeclaration ("System.ComponentModel.DesignerCategoryAttribute");
298                                         att.Arguments.Add (GetArg ("code"));
299                                         AddCustomAttribute (codeClass, att, true);
300                                 }
301                                 else
302                                         codeClass.TypeAttributes = System.Reflection.TypeAttributes.Abstract | System.Reflection.TypeAttributes.Public;
303
304                                 if (binding.Operations.Count == 0) {
305                                         warnings |= ServiceDescriptionImportWarnings.NoMethodsGenerated;
306                                         return;
307                                 }
308                                 
309                                 foreach (OperationBinding oper in binding.Operations) 
310                                 {
311                                         operationBinding = oper;
312                                         operation = FindPortOperation ();
313                                         if (operation == null) throw new Exception ("Operation " + operationBinding.Name + " not found in portType " + PortType.Name);
314
315                                         foreach (OperationMessage omsg in operation.Messages)
316                                         {
317                                                 Message msg = ServiceDescriptions.GetMessage (omsg.Message);
318                                                 if (msg == null) throw new Exception ("Message not found: " + omsg.Message);
319                                                 
320                                                 if (omsg is OperationInput)
321                                                         inputMessage = msg;
322                                                 else
323                                                         outputMessage = msg;
324                                         }
325                                         
326                                         CodeMemberMethod method = GenerateMethod ();
327                                         
328                                         if (method != null)
329                                         {
330                                                 methodName = method.Name;
331                                                 if (operation.Documentation != null && operation.Documentation != "")
332                                                         AddComments (method, operation.Documentation);
333 #if NET_2_0
334                                                 if (Style == ServiceDescriptionImportStyle.Client)
335                                                         AddAsyncMembers (method.Name, method);
336 #endif
337                                         }
338                                 }
339                                 
340 #if NET_2_0
341                         if (Style == ServiceDescriptionImportStyle.Client)
342                                 AddAsyncTypes ();
343 #endif
344                                 
345                                 EndClass ();
346                         }
347                         catch (InvalidOperationException ex)
348                         {
349                                 warnings |= ServiceDescriptionImportWarnings.NoCodeGenerated;
350                                 UnsupportedBindingWarning (ex.Message);
351                         }
352                 }
353
354                 Operation FindPortOperation ()
355                 {
356                         string inMessage = null;
357                         string outMessage = null;
358                         int numMsg = 1;
359                         
360                         if (operationBinding.Input == null) throw new InvalidOperationException ("Input operation binding not found");
361                         inMessage = (operationBinding.Input.Name != null) ? operationBinding.Input.Name : operationBinding.Name;
362                                 
363                         if (operationBinding.Output != null) {
364                                 outMessage = (operationBinding.Output.Name != null) ? operationBinding.Output.Name : operationBinding.Name;
365                                 numMsg++;
366                         }
367                         
368                         string operName = operationBinding.Name;
369                         
370                         Operation foundOper = null;
371                         foreach (Operation oper in PortType.Operations)
372                         {
373                                 if (oper.Name == operName)
374                                 {
375                                         int hits = 0;
376                                         foreach (OperationMessage omsg in oper.Messages)
377                                         {
378                                                 if (omsg is OperationInput && GetOperMessageName (omsg, operName) == inMessage) hits++;
379                                                 if (omsg is OperationOutput && GetOperMessageName (omsg, operName) == outMessage) hits++;
380                                         }
381                                         if (hits == numMsg) return oper;
382                                         foundOper = oper;
383                                 }
384                         }
385                         return foundOper;
386                 }
387                 
388                 string GetOperMessageName (OperationMessage msg, string operName)
389                 {
390                         if (msg.Name == null) return operName;
391                         else return msg.Name;
392                 }
393                 
394                 internal string GetServiceUrl (string location)
395                 {
396                         if (ImportInfo.AppSettingUrlKey == null || ImportInfo.AppSettingUrlKey == string.Empty)
397                                 return location;
398                         else
399                         {
400                                 string url;
401                                 if (Style == ServiceDescriptionImportStyle.Server) throw new InvalidOperationException ("Cannot set appSettingUrlKey if Style is Server");
402                                 url = ConfigurationSettings.AppSettings [ImportInfo.AppSettingUrlKey];
403                                 if (ImportInfo.AppSettingBaseUrl != null && ImportInfo.AppSettingBaseUrl != string.Empty)
404                                         url += "/" + ImportInfo.AppSettingBaseUrl + "/" + location;
405                                 return url;
406                         }
407                 }
408
409                 void ClasifySchemas (ArrayList importInfo)
410                 {
411                         // I don't like this, but I could not find any other way of clasifying
412                         // schemas between encoded and literal.
413                         
414                         xmlSchemas = new XmlSchemas ();
415                         soapSchemas = new XmlSchemas ();
416                         
417                         foreach (ImportInfo info in importInfo)
418                         {
419                                 foreach (Service service in info.ServiceDescription.Services)
420                                 {
421                                         foreach (Port port in service.Ports)
422                                         {
423                                                 this.iinfo = info;
424                                                 this.port = port;
425                                                 binding = ServiceDescriptions.GetBinding (port.Binding);
426                                                 if (binding == null) continue;
427                                                 portType = ServiceDescriptions.GetPortType (binding.Type);
428                                                 if (portType == null) continue;
429                                                 
430                                                 foreach (OperationBinding oper in binding.Operations) 
431                                                 {
432                                                         operationBinding = oper;
433                                                         operation = FindPortOperation ();
434                                                         if (operation == null) continue;
435                 
436                                                         foreach (OperationMessage omsg in operation.Messages)
437                                                         {
438                                                                 Message msg = ServiceDescriptions.GetMessage (omsg.Message);
439                                                                 if (msg == null) continue;
440                                                                 
441                                                                 if (omsg is OperationInput)
442                                                                         inputMessage = msg;
443                                                                 else
444                                                                         outputMessage = msg;
445                                                         }
446                                                         
447                                                         if (GetMessageEncoding (oper.Input) == SoapBindingUse.Encoded)
448                                                                 AddMessageSchema (soapSchemas, oper.Input, inputMessage);
449                                                         else
450                                                                 AddMessageSchema (xmlSchemas, oper.Input, inputMessage);
451                                                         
452                                                         if (oper.Output != null) {
453                                                                 if (GetMessageEncoding (oper.Output) == SoapBindingUse.Encoded)
454                                                                         AddMessageSchema (soapSchemas, oper.Output, outputMessage);
455                                                                 else
456                                                                         AddMessageSchema (xmlSchemas, oper.Output, outputMessage);
457                                                         }
458                                                 }
459                                         }
460                                 }
461                         }
462                         
463                         XmlSchemas defaultList = xmlSchemas;
464                                 
465                         if (xmlSchemas.Count == 0 && soapSchemas.Count > 0)
466                                 defaultList = soapSchemas;
467                                 
468                         // Schemas not referenced by any message
469                         foreach (XmlSchema sc in Schemas)
470                         {
471                                 if (!soapSchemas.Contains (sc) && !xmlSchemas.Contains (sc)) {
472                                         if (ImportsEncodedNamespace (sc))
473                                                 soapSchemas.Add (sc);
474                                         else
475                                                 defaultList.Add (sc);
476                                 }
477                         }
478                 }
479                         
480                 void AddMessageSchema (XmlSchemas schemas, MessageBinding mb, Message msg)
481                 {
482                         foreach (MessagePart part in msg.Parts)
483                         {
484                                 if (part.Element != XmlQualifiedName.Empty)
485                                         AddIncludingSchema (schemas, part.Element.Namespace);
486                                 else if (part.Type != XmlQualifiedName.Empty)
487                                         AddIncludingSchema (schemas, part.Type.Namespace);
488                         }
489                         SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
490                         if (sbb != null) AddIncludingSchema (schemas, sbb.Namespace);
491                 }
492                 
493                 void AddIncludingSchema (XmlSchemas list, string ns)
494                 {
495                         XmlSchema sc = Schemas [ns];
496                         if (sc == null || list.Contains (sc)) return;
497                         list.Add (sc);
498                         foreach (XmlSchemaObject ob in sc.Includes)
499                         {
500                                 XmlSchemaImport import = ob as XmlSchemaImport;
501                                 if (import != null) AddIncludingSchema (list, import.Namespace);
502                         }
503                 }
504                 
505                 SoapBindingUse GetMessageEncoding (MessageBinding mb)
506                 {
507                         SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
508                         if (sbb == null)
509                         {
510                                 if (mb is InputBinding) return SoapBindingUse.Encoded;
511                                 else return SoapBindingUse.Literal;
512                         }
513                         else 
514                                 if (sbb.Use == SoapBindingUse.Encoded) return SoapBindingUse.Encoded;
515                         else
516                                 return SoapBindingUse.Literal;
517                 }
518                 
519                 bool ImportsEncodedNamespace (XmlSchema sc)
520                 {
521                         foreach (XmlSchemaObject ob in sc.Includes)
522                         {
523                                 XmlSchemaImport import = ob as XmlSchemaImport;
524                                 if (import.Namespace == SoapProtocolReflector.EncodingNamespace) return true;
525                         }
526                         return false;
527                 }
528                 
529 #if NET_2_0
530
531                 void AddAsyncTypes ()
532                 {
533                         foreach (CodeTypeDeclaration type in asyncTypes)
534                                 codeNamespace.Types.Add (type);
535                         asyncTypes.Clear ();
536                 }
537
538                 void AddAsyncMembers (string messageName, CodeMemberMethod method)
539                 {
540                         CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
541                         CodePrimitiveExpression enull = new CodePrimitiveExpression (null);
542                         
543                         CodeMemberField codeField = new CodeMemberField (typeof(System.Threading.SendOrPostCallback), messageName + "OperationCompleted");
544                         codeField.Attributes = MemberAttributes.Private;
545                         CodeTypeDeclaration.Members.Add (codeField);
546                         
547                         // Event arguments class
548                         
549                         string argsClassName = classNames.AddUnique (messageName + "CompletedEventArgs", null);
550                         CodeTypeDeclaration argsClass = new CodeTypeDeclaration (argsClassName);
551                         argsClass.BaseTypes.Add (new CodeTypeReference ("System.ComponentModel.AsyncCompletedEventArgs"));
552
553                         CodeMemberField resultsField = new CodeMemberField (typeof(object[]), "results");
554                         resultsField.Attributes = MemberAttributes.Private;
555                         argsClass.Members.Add (resultsField);
556                         
557                         CodeConstructor cc = new CodeConstructor ();
558                         cc.Attributes = MemberAttributes.Assembly;
559                         cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object[]), "results"));
560                         cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(System.Exception), "exception"));
561                         cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(bool), "cancelled"));
562                         cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "userState"));
563                         cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("exception"));
564                         cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("cancelled"));
565                         cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("userState"));
566                         CodeExpression thisResults = new CodeFieldReferenceExpression (ethis, "results");
567                         cc.Statements.Add (new CodeAssignStatement (thisResults, new CodeVariableReferenceExpression ("results")));
568                         argsClass.Members.Add (cc);
569                         
570                         int ind = 0;
571                         
572                         if (method.ReturnType.BaseType != "System.Void")
573                                 argsClass.Members.Add (CreateArgsProperty (method.ReturnType, "Result", ind++));
574                         
575                         foreach (CodeParameterDeclarationExpression par in method.Parameters) 
576                         {
577                                 if (par.Direction == FieldDirection.Out || par.Direction == FieldDirection.Ref)
578                                         argsClass.Members.Add (CreateArgsProperty (par.Type, par.Name, ind++));
579                         }
580                         
581                         bool needsArgsClass = (ind > 0);
582                         if (needsArgsClass)
583                                 asyncTypes.Add (argsClass);
584                         else
585                                 argsClassName = "System.ComponentModel.AsyncCompletedEventArgs";
586                         
587                         // Event delegate type
588                         
589                         CodeTypeDelegate delegateType = new CodeTypeDelegate (messageName + "CompletedEventHandler");
590                         delegateType.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "sender"));
591                         delegateType.Parameters.Add (new CodeParameterDeclarationExpression (argsClassName, "args"));
592                         
593                         // Event member
594                         
595                         CodeMemberEvent codeEvent = new CodeMemberEvent ();
596                         codeEvent.Name = messageName + "Completed";
597                         codeEvent.Type = new CodeTypeReference (delegateType.Name);
598                         CodeTypeDeclaration.Members.Add (codeEvent);
599                         
600                         // Async method (without user state param)
601                         
602                         CodeMemberMethod am = new CodeMemberMethod ();
603                         am.Attributes = MemberAttributes.Public | MemberAttributes.Final;
604                         am.Name = method.Name + "Async";
605                         am.ReturnType = new CodeTypeReference (typeof(void));
606                         CodeMethodInvokeExpression inv;
607                         inv = new CodeMethodInvokeExpression (ethis, am.Name);
608                         am.Statements.Add (inv);
609                         
610                         // On...Completed method
611                         
612                         CodeMemberMethod onCompleted = new CodeMemberMethod ();
613                         onCompleted.Name = "On" + messageName + "Completed";
614                         onCompleted.Attributes = MemberAttributes.Private | MemberAttributes.Final;
615                         onCompleted.ReturnType = new CodeTypeReference (typeof(void));
616                         onCompleted.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "arg"));
617                         
618                         CodeConditionStatement anIf = new CodeConditionStatement ();
619                         
620                         CodeExpression eventField = new CodeEventReferenceExpression (ethis, codeEvent.Name);
621                         anIf.Condition = new CodeBinaryOperatorExpression (eventField, CodeBinaryOperatorType.IdentityInequality, enull);
622                         CodeExpression castedArg = new CodeCastExpression (typeof(System.Web.Services.Protocols.InvokeCompletedEventArgs), new CodeVariableReferenceExpression ("arg"));
623                         CodeStatement invokeArgs = new CodeVariableDeclarationStatement (typeof(System.Web.Services.Protocols.InvokeCompletedEventArgs), "invokeArgs", castedArg);
624                         anIf.TrueStatements.Add (invokeArgs);
625                         
626                         CodeDelegateInvokeExpression delegateInvoke = new CodeDelegateInvokeExpression ();
627                         delegateInvoke.TargetObject = eventField;
628                         delegateInvoke.Parameters.Add (ethis);
629                         CodeObjectCreateExpression argsInstance = new CodeObjectCreateExpression (argsClassName);
630                         CodeExpression invokeArgsVar = new CodeVariableReferenceExpression ("invokeArgs");
631                         if (needsArgsClass) argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Results"));
632                         argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Error"));
633                         argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Cancelled"));
634                         argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "UserState"));
635                         delegateInvoke.Parameters.Add (argsInstance);
636                         anIf.TrueStatements.Add (delegateInvoke);
637                         
638                         onCompleted.Statements.Add (anIf);
639                         
640                         // Async method
641                         
642                         CodeMemberMethod asyncMethod = new CodeMemberMethod ();
643                         asyncMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
644                         asyncMethod.Name = method.Name + "Async";
645                         asyncMethod.ReturnType = new CodeTypeReference (typeof(void));
646                         
647                         CodeExpression delegateField = new CodeFieldReferenceExpression (ethis, codeField.Name);
648                         anIf = new CodeConditionStatement ();
649                         anIf.Condition = new CodeBinaryOperatorExpression (delegateField, CodeBinaryOperatorType.IdentityEquality, enull);;
650                         CodeExpression delegateRef = new CodeMethodReferenceExpression (ethis, onCompleted.Name);
651                         CodeExpression newDelegate = new CodeObjectCreateExpression (typeof(System.Threading.SendOrPostCallback), delegateRef);
652                         CodeAssignStatement cas = new CodeAssignStatement (delegateField, newDelegate);
653                         anIf.TrueStatements.Add (cas);
654                         asyncMethod.Statements.Add (anIf);
655                         
656                         CodeArrayCreateExpression paramsArray = new CodeArrayCreateExpression (typeof(object));
657                         
658                         // Assign parameters
659                         
660                         CodeIdentifiers paramsIds = new CodeIdentifiers ();
661                         
662                         foreach (CodeParameterDeclarationExpression par in method.Parameters) 
663                         {
664                                 paramsIds.Add (par.Name, null);
665                                 if (par.Direction == FieldDirection.In || par.Direction == FieldDirection.Ref) {
666                                         CodeParameterDeclarationExpression inpar = new CodeParameterDeclarationExpression (par.Type, par.Name);
667                                         am.Parameters.Add (inpar);
668                                         asyncMethod.Parameters.Add (inpar);
669                                         inv.Parameters.Add (new CodeVariableReferenceExpression (par.Name));
670                                         paramsArray.Initializers.Add (new CodeVariableReferenceExpression (par.Name));
671                                 }
672                         }
673
674
675                         inv.Parameters.Add (enull);
676                         
677                         string userStateName = paramsIds.AddUnique ("userState", null);
678                         asyncMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), userStateName));
679                         
680                         CodeExpression userStateVar = new CodeVariableReferenceExpression (userStateName);
681                         asyncMethod.Statements.Add (BuildInvokeAsync (messageName, paramsArray, delegateField, userStateVar));
682                         
683                         CodeTypeDeclaration.Members.Add (am);
684                         CodeTypeDeclaration.Members.Add (asyncMethod);
685                         CodeTypeDeclaration.Members.Add (onCompleted);
686                         
687                         asyncTypes.Add (delegateType);
688                 }
689                 
690                 CodeMemberProperty CreateArgsProperty (CodeTypeReference type, string name, int ind)
691                 {
692                         CodeMemberProperty prop = new CodeMemberProperty ();
693                         prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
694                         prop.HasGet = true;
695                         prop.HasSet = false;
696                         prop.Name = name;
697                         prop.Type = type;
698                         CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
699                         CodeExpression thisResults = new CodeFieldReferenceExpression (ethis, "results");
700                         prop.GetStatements.Add (new CodeMethodInvokeExpression (ethis, "RaiseExceptionIfNecessary"));
701                         CodeArrayIndexerExpression arrValue = new CodeArrayIndexerExpression (thisResults, new CodePrimitiveExpression (ind));
702                         CodeExpression retval = new CodeCastExpression (type, arrValue);
703                         prop.GetStatements.Add (new CodeMethodReturnStatement (retval));
704                         return prop;
705                 }
706                 
707                 internal virtual CodeExpression BuildInvokeAsync (string messageName, CodeArrayCreateExpression paramsArray, CodeExpression delegateField, CodeExpression userStateVar)
708                 {
709                         CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
710                         CodeMethodInvokeExpression inv2 = new CodeMethodInvokeExpression (ethis, "InvokeAsync");
711                         inv2.Parameters.Add (new CodePrimitiveExpression (messageName));
712                         inv2.Parameters.Add (paramsArray);
713                         inv2.Parameters.Add (delegateField);
714                         inv2.Parameters.Add (userStateVar);
715                         return inv2;
716                 }
717 #endif
718                 
719                 [MonoTODO]
720                 public void AddExtensionWarningComments (CodeCommentStatementCollection comments, ServiceDescriptionFormatExtensionCollection extensions) 
721                 {
722                         throw new NotImplementedException ();
723                 }
724
725                 protected abstract CodeTypeDeclaration BeginClass ();
726
727                 protected virtual void BeginNamespace ()
728                 {
729                 }
730
731                 protected virtual void EndClass ()
732                 {
733                 }
734
735                 protected virtual void EndNamespace ()
736                 {
737                 }
738
739                 protected abstract CodeMemberMethod GenerateMethod ();
740                 protected abstract bool IsBindingSupported ();
741                 protected abstract bool IsOperationFlowSupported (OperationFlow flow);
742                 
743                 [MonoTODO]
744                 public Exception OperationBindingSyntaxException (string text)
745                 {
746                         throw new NotImplementedException ();
747                 }
748
749                 [MonoTODO]
750                 public Exception OperationSyntaxException (string text)
751                 {
752                         throw new NotImplementedException ();
753                 }
754
755                 public void UnsupportedBindingWarning (string text)
756                 {
757                         warnings |= ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored;
758                         AddGlobalComments ("WARNING: Could not generate proxy for binding " + binding.Name + ". " + text);
759                 }
760
761                 public void UnsupportedOperationBindingWarning (string text)
762                 {
763                         warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
764                         AddGlobalComments ("WARNING: Could not generate operation " + OperationBinding.Name + ". " + text);
765                 }
766
767                 public void UnsupportedOperationWarning (string text)
768                 {
769                         warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
770                         AddGlobalComments ("WARNING: Could not generate operation " + OperationBinding.Name + ". " + text);
771                 }
772
773                 void AddGlobalComments (string comments)
774                 {
775                         codeNamespace.Comments.Add (new CodeCommentStatement (comments, false));
776                 }
777
778                 void AddComments (CodeTypeMember member, string comments)
779                 {
780                         if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
781                         else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
782                 }
783
784                 void AddCodeType (CodeTypeDeclaration type, string comments)
785                 {
786                         AddComments (type, comments);
787                         codeNamespace.Types.Add (type);
788                 }
789
790                 internal void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
791                 {
792                         if (att.Arguments.Count == 0 && !addIfNoParams) return;
793                         
794                         if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
795                         ctm.CustomAttributes.Add (att);
796                 }
797
798                 internal void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
799                 {
800                         if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
801                         ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
802                 }
803
804                 internal CodeAttributeArgument GetArg (string name, object value)
805                 {
806                         return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
807                 }
808
809                 internal CodeAttributeArgument GetEnumArg (string name, string enumType, string enumValue)
810                 {
811                         return new CodeAttributeArgument (name, new CodeFieldReferenceExpression (new CodeTypeReferenceExpression(enumType), enumValue));
812                 }
813
814                 internal CodeAttributeArgument GetArg (object value)
815                 {
816                         return new CodeAttributeArgument (new CodePrimitiveExpression(value));
817                 }
818
819                 internal CodeAttributeArgument GetTypeArg (string name, string typeName)
820                 {
821                         return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
822                 }
823                 
824                 #endregion
825         }
826 }