2 // ServiceContractGenerator.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.ComponentModel;
33 using System.Configuration;
35 using System.Reflection;
36 using System.Runtime.Serialization;
37 using System.ServiceModel;
38 using System.ServiceModel.Channels;
39 using System.ServiceModel.Configuration;
40 using System.Threading;
41 using System.Xml.Schema;
42 using System.Xml.Serialization;
44 using ConfigurationType = System.Configuration.Configuration;
45 using QName = System.Xml.XmlQualifiedName;
46 using OPair = System.Collections.Generic.KeyValuePair<System.ServiceModel.Description.IOperationContractGenerationExtension,System.ServiceModel.Description.OperationContractGenerationContext>;
48 namespace System.ServiceModel.Description
50 public class ServiceContractGenerator
53 ConfigurationType config;
54 Collection<MetadataConversionError> errors
55 = new Collection<MetadataConversionError> ();
56 Dictionary<string,string> nsmappings
57 = new Dictionary<string,string> ();
58 Dictionary<ContractDescription,Type> referenced_types
59 = new Dictionary<ContractDescription,Type> ();
60 ServiceContractGenerationOptions options;
61 Dictionary<QName, QName> imported_names = null;
62 ServiceContractGenerationContext contract_context;
63 List<OPair> operation_contexts = new List<OPair> ();
65 XsdDataContractImporter xsd_data_importer;
67 public ServiceContractGenerator ()
72 public ServiceContractGenerator (CodeCompileUnit ccu)
77 public ServiceContractGenerator (ConfigurationType config)
82 public ServiceContractGenerator (CodeCompileUnit ccu, ConfigurationType config)
85 this.ccu = new CodeCompileUnit ();
89 Options |= ServiceContractGenerationOptions.ChannelInterface |
90 ServiceContractGenerationOptions.ClientClass;
93 public ConfigurationType Configuration {
94 get { return config; }
97 public Collection<MetadataConversionError> Errors {
98 get { return errors; }
101 public Dictionary<string,string> NamespaceMappings {
102 get { return nsmappings; }
105 public ServiceContractGenerationOptions Options {
106 get { return options; }
107 set { options = value; }
111 get { return GenerateEventBasedAsync || (options & ServiceContractGenerationOptions.AsynchronousMethods) != 0; }
114 bool GenerateEventBasedAsync {
115 get { return (options & ServiceContractGenerationOptions.EventBasedAsynchronousMethods) != 0; }
118 public Dictionary<ContractDescription,Type> ReferencedTypes {
119 get { return referenced_types; }
122 public CodeCompileUnit TargetCompileUnit {
127 public void GenerateBinding (Binding binding,
128 out string bindingSectionName,
129 out string configurationName)
131 throw new NotImplementedException ();
134 #region Service Contract Type
136 // Those implementation classes are very likely to be split
137 // into different classes.
140 public CodeTypeReference GenerateServiceContractType (
141 ContractDescription contractDescription)
143 CodeNamespace cns = GetNamespace (contractDescription.Namespace);
144 imported_names = new Dictionary<QName, QName> ();
145 var ret = ExportInterface (contractDescription, cns);
147 // FIXME: handle duplex callback
149 if ((Options & ServiceContractGenerationOptions.ChannelInterface) != 0)
150 GenerateChannelInterface (contractDescription, cns);
152 if ((Options & ServiceContractGenerationOptions.ClientClass) != 0)
153 GenerateProxyClass (contractDescription, cns);
155 if (xsd_data_importer != null)
156 MergeCompileUnit (xsd_data_importer.CodeCompileUnit, ccu);
158 // Process extensions. Class first, then methods.
159 // (built-in ones must present before processing class extensions).
160 foreach (var cb in contractDescription.Behaviors) {
161 var gex = cb as IServiceContractGenerationExtension;
163 gex.GenerateContract (contract_context);
165 foreach (var opair in operation_contexts)
166 opair.Key.GenerateOperation (opair.Value);
171 CodeNamespace GetNamespace (string ns)
175 foreach (CodeNamespace cns in ccu.Namespaces)
178 CodeNamespace ncns = new CodeNamespace ();
180 ccu.Namespaces.Add (ncns);
184 CodeTypeDeclaration GetTypeDeclaration (CodeNamespace cns, string name)
186 foreach (CodeTypeDeclaration type in cns.Types)
187 if (type.Name == name)
192 void GenerateProxyClass (ContractDescription cd, CodeNamespace cns)
194 string name = cd.Name + "Client";
196 name = name.Substring (1);
197 CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
199 return; // already imported
200 CodeTypeReference clientBase = new CodeTypeReference (typeof (ClientBase<>));
201 clientBase.TypeArguments.Add (new CodeTypeReference (cd.Name));
202 type = new CodeTypeDeclaration (name);
203 cns.Types.Add (type);
204 type.TypeAttributes = TypeAttributes.Public;
205 type.BaseTypes.Add (clientBase);
206 type.BaseTypes.Add (new CodeTypeReference (cd.Name));
209 CodeConstructor ctor = new CodeConstructor ();
210 ctor.Attributes = MemberAttributes.Public;
211 type.Members.Add (ctor);
213 // .ctor(string endpointConfigurationName)
214 ctor = new CodeConstructor ();
215 ctor.Attributes = MemberAttributes.Public;
216 ctor.Parameters.Add (
217 new CodeParameterDeclarationExpression (
218 new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
219 ctor.BaseConstructorArgs.Add (
220 new CodeArgumentReferenceExpression ("endpointConfigurationName"));
221 type.Members.Add (ctor);
223 // .ctor(string endpointConfigurationName, string remoteAddress)
224 ctor = new CodeConstructor ();
225 ctor.Attributes = MemberAttributes.Public;
226 ctor.Parameters.Add (
227 new CodeParameterDeclarationExpression (
228 new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
229 ctor.Parameters.Add (
230 new CodeParameterDeclarationExpression (
231 new CodeTypeReference (typeof (string)), "remoteAddress"));
232 ctor.BaseConstructorArgs.Add (
233 new CodeArgumentReferenceExpression ("endpointConfigurationName"));
234 ctor.BaseConstructorArgs.Add (
235 new CodeArgumentReferenceExpression ("remoteAddress"));
236 type.Members.Add (ctor);
238 // .ctor(string endpointConfigurationName, EndpointAddress remoteAddress)
239 ctor = new CodeConstructor ();
240 ctor.Attributes = MemberAttributes.Public;
241 ctor.Parameters.Add (
242 new CodeParameterDeclarationExpression (
243 new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
244 ctor.Parameters.Add (
245 new CodeParameterDeclarationExpression (
246 new CodeTypeReference (typeof (EndpointAddress)), "remoteAddress"));
247 ctor.BaseConstructorArgs.Add (
248 new CodeArgumentReferenceExpression ("endpointConfigurationName"));
249 ctor.BaseConstructorArgs.Add (
250 new CodeArgumentReferenceExpression ("remoteAddress"));
251 type.Members.Add (ctor);
253 // .ctor(Binding,EndpointAddress)
254 ctor = new CodeConstructor ();
255 ctor.Attributes = MemberAttributes.Public;
256 ctor.Parameters.Add (
257 new CodeParameterDeclarationExpression (
258 new CodeTypeReference (typeof (Binding)), "binding"));
259 ctor.Parameters.Add (
260 new CodeParameterDeclarationExpression (
261 new CodeTypeReference (typeof (EndpointAddress)), "endpoint"));
262 ctor.BaseConstructorArgs.Add (
263 new CodeArgumentReferenceExpression ("binding"));
264 ctor.BaseConstructorArgs.Add (
265 new CodeArgumentReferenceExpression ("endpoint"));
266 type.Members.Add (ctor);
268 // service contract methods
269 AddImplementationClientMethods (type, cd);
271 if (GenerateEventBasedAsync)
272 foreach (var od in cd.Operations)
273 GenerateEventBasedAsyncSupport (type, od, cns);
276 void GenerateChannelInterface (ContractDescription cd, CodeNamespace cns)
278 string name = cd.Name + "Channel";
279 CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
283 type = new CodeTypeDeclaration ();
285 type.TypeAttributes = TypeAttributes.Interface | TypeAttributes.Public;
286 cns.Types.Add (type);
288 type.BaseTypes.Add (ExportInterface (cd, cns));
289 type.BaseTypes.Add (new CodeTypeReference (typeof (System.ServiceModel.IClientChannel)));
292 CodeTypeReference ExportInterface (ContractDescription cd, CodeNamespace cns)
294 CodeTypeDeclaration type = GetTypeDeclaration (cns, cd.Name);
296 return new CodeTypeReference (type.Name);
297 type = new CodeTypeDeclaration ();
298 type.TypeAttributes = TypeAttributes.Interface;
299 type.TypeAttributes |= TypeAttributes.Public;
300 cns.Types.Add (type);
302 CodeAttributeDeclaration ad =
303 new CodeAttributeDeclaration (
304 new CodeTypeReference (
305 typeof (ServiceContractAttribute)));
306 ad.Arguments.Add (new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (cd.Namespace)));
307 type.CustomAttributes.Add (ad);
308 contract_context = new ServiceContractGenerationContext (this, cd, type);
310 AddOperationMethods (type, cd);
312 return new CodeTypeReference (type.Name);
315 void AddBeginAsyncArgs (CodeMemberMethod cm)
317 var acb = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback");
318 cm.Parameters.Add (acb);
319 var us = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState");
320 cm.Parameters.Add (us);
323 void AddOperationMethods (CodeTypeDeclaration type, ContractDescription cd)
325 foreach (OperationDescription od in cd.Operations) {
326 CodeMemberMethod syncMethod = null, beginMethod = null, endMethod = null;
328 CodeTypeReference returnTypeFromMessageContract = null;
329 syncMethod = GenerateOperationMethod (type, cd, od, false, out returnTypeFromMessageContract);
330 type.Members.Add (syncMethod);
333 beginMethod = GenerateOperationMethod (type, cd, od, true, out returnTypeFromMessageContract);
334 type.Members.Add (beginMethod);
336 var cm = new CodeMemberMethod ();
337 type.Members.Add (cm);
338 cm.Name = "End" + od.Name;
341 var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
342 cm.Parameters.Add (res);
344 if (od.SyncMethod != null) // FIXME: it depends on sync method!
345 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
347 cm.ReturnType = returnTypeFromMessageContract;
350 foreach (var ob in od.Behaviors) {
351 var gex = ob as IOperationContractGenerationExtension;
353 operation_contexts.Add (new OPair (gex, new OperationContractGenerationContext (this, contract_context, od, type, syncMethod, beginMethod, endMethod)));
358 CodeMemberMethod GenerateOperationMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnType)
360 CodeMemberMethod cm = new CodeMemberMethod ();
363 cm.Name = "Begin" + od.Name;
367 if (od.SyncMethod != null) {
368 ExportParameters (cm, od.SyncMethod.GetParameters ());
370 AddBeginAsyncArgs (cm);
371 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
374 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
375 returnType = new CodeTypeReference (od.SyncMethod.ReturnType);
377 ExportMessages (od.Messages, cm, false);
378 returnType = cm.ReturnType;
380 AddBeginAsyncArgs (cm);
381 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
385 // [OperationContract (Action = "...", ReplyAction = "..")]
386 var ad = new CodeAttributeDeclaration (new CodeTypeReference (typeof (OperationContractAttribute)));
387 foreach (MessageDescription md in od.Messages) {
388 if (md.Direction == MessageDirection.Input)
389 ad.Arguments.Add (new CodeAttributeArgument ("Action", new CodePrimitiveExpression (md.Action)));
391 ad.Arguments.Add (new CodeAttributeArgument ("ReplyAction", new CodePrimitiveExpression (md.Action)));
394 ad.Arguments.Add (new CodeAttributeArgument ("AsyncPattern", new CodePrimitiveExpression (true)));
395 cm.CustomAttributes.Add (ad);
400 void ExportParameters (CodeMemberMethod method, ParameterInfo [] parameters)
402 foreach (ParameterInfo pi in parameters)
403 method.Parameters.Add (
404 new CodeParameterDeclarationExpression (
405 new CodeTypeReference (pi.ParameterType),
409 void AddImplementationClientMethods (CodeTypeDeclaration type, ContractDescription cd)
411 foreach (OperationDescription od in cd.Operations) {
413 CodeTypeReference returnTypeFromMessageContract = null;
414 cm = GenerateImplementationClientMethod (type, cd, od, false, out returnTypeFromMessageContract);
415 type.Members.Add (cm);
420 cm = GenerateImplementationClientMethod (type, cd, od, true, out returnTypeFromMessageContract);
421 type.Members.Add (cm);
423 // EndXxx() implementation
425 cm = new CodeMemberMethod ();
426 cm.Attributes = MemberAttributes.Public
427 | MemberAttributes.Final;
428 type.Members.Add (cm);
429 cm.Name = "End" + od.Name;
431 var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
432 cm.Parameters.Add (res);
434 if (od.SyncMethod != null) // FIXME: it depends on sync method!
435 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
437 cm.ReturnType = returnTypeFromMessageContract;
439 string resultArgName = "result";
440 if (od.EndMethod != null)
441 resultArgName = od.EndMethod.GetParameters () [0].Name;
443 var call = new CodeMethodInvokeExpression (
444 new CodePropertyReferenceExpression (
445 new CodeBaseReferenceExpression (),
448 new CodeArgumentReferenceExpression (resultArgName));
450 if (cm.ReturnType.BaseType == "System.Void")
451 cm.Statements.Add (new CodeExpressionStatement (call));
453 cm.Statements.Add (new CodeMethodReturnStatement (call));
457 CodeMemberMethod GenerateImplementationClientMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnTypeFromMessageContract)
459 CodeMemberMethod cm = new CodeMemberMethod ();
461 cm.Name = "Begin" + od.Name;
464 cm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
465 returnTypeFromMessageContract = null;
467 List<CodeExpression> args = new List<CodeExpression> ();
468 if (od.SyncMethod != null) {
469 ParameterInfo [] pars = od.SyncMethod.GetParameters ();
470 ExportParameters (cm, pars);
471 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
473 foreach (ParameterInfo pi in pars)
474 args.Add (new CodeArgumentReferenceExpression (pi.Name));
476 args.AddRange (ExportMessages (od.Messages, cm, true));
477 returnTypeFromMessageContract = cm.ReturnType;
479 AddBeginAsyncArgs (cm);
480 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
484 args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
485 args.Add (new CodeArgumentReferenceExpression ("userState"));
488 CodeExpression call = new CodeMethodInvokeExpression (
489 new CodePropertyReferenceExpression (
490 new CodeBaseReferenceExpression (),
495 if (cm.ReturnType.BaseType == "System.Void")
496 cm.Statements.Add (new CodeExpressionStatement (call));
498 cm.Statements.Add (new CodeMethodReturnStatement (call));
502 CodeMemberMethod FindByName (CodeTypeDeclaration type, string name)
504 foreach (var m in type.Members) {
505 var method = m as CodeMemberMethod;
506 if (method != null && method.Name == name)
512 void GenerateEventBasedAsyncSupport (CodeTypeDeclaration type, OperationDescription od, CodeNamespace cns)
514 var method = FindByName (type, od.Name) ?? FindByName (type, "Begin" + od.Name);
515 var endMethod = method.Name == od.Name ? null : FindByName (type, "End" + od.Name);
516 bool methodAsync = method.Name.StartsWith ("Begin", StringComparison.Ordinal);
518 var thisExpr = new CodeThisReferenceExpression ();
519 var baseExpr = new CodeBaseReferenceExpression ();
520 var nullExpr = new CodePrimitiveExpression (null);
521 var asyncResultType = new CodeTypeReference (typeof (IAsyncResult));
523 // OnBeginXxx() implementation
524 var cm = new CodeMemberMethod () {
525 Name = "OnBegin" + od.Name,
526 Attributes = MemberAttributes.Private | MemberAttributes.Final,
527 ReturnType = asyncResultType
529 type.Members.Add (cm);
531 AddMethodParam (cm, typeof (object []), "args");
532 AddMethodParam (cm, typeof (AsyncCallback), "asyncCallback");
533 AddMethodParam (cm, typeof (object), "userState");
535 var call = new CodeMethodInvokeExpression (
538 for (int idx = 0; idx < method.Parameters.Count - (methodAsync ? 2 : 0); idx++) {
539 var p = method.Parameters [idx];
540 cm.Statements.Add (new CodeVariableDeclarationStatement (p.Type, p.Name, new CodeCastExpression (p.Type, new CodeArrayIndexerExpression (new CodeArgumentReferenceExpression ("args"), new CodePrimitiveExpression (idx)))));
541 call.Parameters.Add (new CodeVariableReferenceExpression (p.Name));
543 call.Parameters.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
544 call.Parameters.Add (new CodeArgumentReferenceExpression ("userState"));
545 cm.Statements.Add (new CodeMethodReturnStatement (call));
547 // OnEndXxx() implementation
548 cm = new CodeMemberMethod () {
549 Name = "OnEnd" + od.Name,
550 Attributes = MemberAttributes.Private | MemberAttributes.Final,
551 ReturnType = new CodeTypeReference (typeof (object [])) };
552 type.Members.Add (cm);
554 AddMethodParam (cm, typeof (IAsyncResult), "result");
556 var outArgRefs = new List<CodeVariableReferenceExpression> ();
558 for (int idx = 0; idx < method.Parameters.Count; idx++) {
559 var p = method.Parameters [idx];
560 if (p.Direction != FieldDirection.In) {
561 cm.Statements.Add (new CodeVariableDeclarationStatement (p.Type, p.Name));
562 outArgRefs.Add (new CodeVariableReferenceExpression (p.Name)); // FIXME: should this work? They need "out" or "ref" modifiers.
566 call = new CodeMethodInvokeExpression (
569 new CodeArgumentReferenceExpression ("result"));
570 call.Parameters.AddRange (outArgRefs.Cast<CodeExpression> ().ToArray ()); // questionable
572 cm.Statements.Add (new CodeVariableDeclarationStatement (typeof (object), "__ret", call));
573 var retCreate = new CodeArrayCreateExpression (typeof (object));
574 retCreate.Initializers.Add (new CodeVariableReferenceExpression ("__ret"));
575 foreach (var outArgRef in outArgRefs)
576 retCreate.Initializers.Add (new CodeVariableReferenceExpression (outArgRef.VariableName));
578 cm.Statements.Add (new CodeMethodReturnStatement (retCreate));
580 // OnXxxCompleted() implementation
581 cm = new CodeMemberMethod () {
582 Name = "On" + od.Name + "Completed",
583 Attributes = MemberAttributes.Private | MemberAttributes.Final };
584 type.Members.Add (cm);
586 AddMethodParam (cm, typeof (object), "state");
588 var iaargs = new CodeTypeReference ("InvokeAsyncCompletedEventArgs"); // avoid messy System.Type instance for generic nested type :|
589 var iaref = new CodeVariableReferenceExpression ("args");
590 var methodEventArgs = new CodeObjectCreateExpression (new CodeTypeReference (od.Name + "CompletedEventArgs"),
591 new CodePropertyReferenceExpression (iaref, "Results"),
592 new CodePropertyReferenceExpression (iaref, "Error"),
593 new CodePropertyReferenceExpression (iaref, "Cancelled"),
594 new CodePropertyReferenceExpression (iaref, "UserState"));
595 cm.Statements.Add (new CodeConditionStatement (
596 new CodeBinaryOperatorExpression (
597 new CodeEventReferenceExpression (thisExpr, od.Name + "Completed"), CodeBinaryOperatorType.IdentityInequality, nullExpr),
598 new CodeVariableDeclarationStatement (iaargs, "args", new CodeCastExpression (iaargs, new CodeArgumentReferenceExpression ("state"))),
599 new CodeExpressionStatement (new CodeMethodInvokeExpression (thisExpr, od.Name + "Completed", thisExpr, methodEventArgs))));
602 type.Members.Add (new CodeMemberField (new CodeTypeReference ("BeginOperationDelegate"), "onBegin" + od.Name + "Delegate"));
603 type.Members.Add (new CodeMemberField (new CodeTypeReference ("EndOperationDelegate"), "onEnd" + od.Name + "Delegate"));
604 type.Members.Add (new CodeMemberField (new CodeTypeReference (typeof (SendOrPostCallback)), "on" + od.Name + "CompletedDelegate"));
606 // XxxCompletedEventArgs class
607 var argsType = new CodeTypeDeclaration (od.Name + "CompletedEventArgs");
608 argsType.BaseTypes.Add (new CodeTypeReference (typeof (AsyncCompletedEventArgs)));
609 cns.Types.Add (argsType);
611 var argsCtor = new CodeConstructor () {
612 Attributes = MemberAttributes.Public | MemberAttributes.Final };
613 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object []), "results"));
614 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (Exception), "error"));
615 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (bool), "cancelled"));
616 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
617 argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("error"));
618 argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("cancelled"));
619 argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("userState"));
620 var resultsField = new CodeFieldReferenceExpression (thisExpr, "results");
621 argsCtor.Statements.Add (new CodeAssignStatement (resultsField, new CodeArgumentReferenceExpression ("results")));
622 argsType.Members.Add (argsCtor);
624 argsType.Members.Add (new CodeMemberField (typeof (object []), "results"));
626 var resultProp = new CodeMemberProperty {
628 Type = endMethod != null ? endMethod.ReturnType : method.ReturnType,
629 Attributes = MemberAttributes.Public | MemberAttributes.Final };
630 resultProp.GetStatements.Add (new CodeMethodReturnStatement (new CodeCastExpression (resultProp.Type, new CodeArrayIndexerExpression (resultsField, new CodePrimitiveExpression (0)))));
631 argsType.Members.Add (resultProp);
634 var handlerType = new CodeTypeReference (typeof (EventHandler<>));
635 handlerType.TypeArguments.Add (new CodeTypeReference (argsType.Name));
636 type.Members.Add (new CodeMemberEvent () {
637 Name = od.Name + "Completed",
639 Attributes = MemberAttributes.Public | MemberAttributes.Final });
641 // XxxAsync() implementations
642 bool hasAsync = false;
643 foreach (int __x in Enumerable.Range (0, 2)) {
644 cm = new CodeMemberMethod ();
645 type.Members.Add (cm);
646 cm.Name = od.Name + "Async";
647 cm.Attributes = MemberAttributes.Public
648 | MemberAttributes.Final;
650 var inArgs = new List<CodeParameterDeclarationExpression > ();
652 for (int idx = 0; idx < method.Parameters.Count - (methodAsync ? 2 : 0); idx++) {
653 var pd = method.Parameters [idx];
655 cm.Parameters.Add (pd);
658 // First one is overload without asyncState arg.
660 call = new CodeMethodInvokeExpression (thisExpr, cm.Name, inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ());
661 call.Parameters.Add (nullExpr);
662 cm.Statements.Add (new CodeExpressionStatement (call));
667 // Second one is the primary one.
669 cm.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
671 // if (onBeginBarOperDelegate == null) onBeginBarOperDelegate = new BeginOperationDelegate (OnBeginBarOper);
672 // if (onEndBarOperDelegate == null) onEndBarOperDelegate = new EndOperationDelegate (OnEndBarOper);
673 // if (onBarOperCompletedDelegate == null) onBarOperCompletedDelegate = new BeginOperationDelegate (OnBarOperCompleted);
674 var beginOperDelegateRef = new CodeFieldReferenceExpression (thisExpr, "onBegin" + od.Name + "Delegate");
675 var endOperDelegateRef = new CodeFieldReferenceExpression (thisExpr, "onEnd" + od.Name + "Delegate");
676 var operCompletedDelegateRef = new CodeFieldReferenceExpression (thisExpr, "on" + od.Name + "CompletedDelegate");
678 var ifstmt = new CodeConditionStatement (
679 new CodeBinaryOperatorExpression (beginOperDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
680 new CodeAssignStatement (beginOperDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference ("BeginOperationDelegate"), thisExpr, "OnBegin" + od.Name)));
681 cm.Statements.Add (ifstmt);
682 ifstmt = new CodeConditionStatement (
683 new CodeBinaryOperatorExpression (endOperDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
684 new CodeAssignStatement (endOperDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference ("EndOperationDelegate"), thisExpr, "OnEnd" + od.Name)));
685 cm.Statements.Add (ifstmt);
686 ifstmt = new CodeConditionStatement (
687 new CodeBinaryOperatorExpression (operCompletedDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
688 new CodeAssignStatement (operCompletedDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference (typeof (SendOrPostCallback)), thisExpr, "On" + od.Name + "Completed")));
689 cm.Statements.Add (ifstmt);
691 // InvokeAsync (onBeginBarOperDelegate, inValues, onEndBarOperDelegate, onBarOperCompletedDelegate, userState);
693 inArgs.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
695 var args = new List<CodeExpression> ();
696 args.Add (beginOperDelegateRef);
697 args.Add (new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
698 args.Add (endOperDelegateRef);
699 args.Add (new CodeFieldReferenceExpression (thisExpr, "on" + od.Name + "CompletedDelegate"));
700 args.Add (new CodeArgumentReferenceExpression ("userState"));
701 call = new CodeMethodInvokeExpression (baseExpr, "InvokeAsync", args.ToArray ());
702 cm.Statements.Add (new CodeExpressionStatement (call));
706 void AddMethodParam (CodeMemberMethod cm, Type type, string name)
708 cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (type), name));
711 const string ms_arrays_ns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
713 string GetCodeTypeName (QName mappedTypeName)
715 if (mappedTypeName.Namespace == ms_arrays_ns)
716 return DataContractSerializerMessageContractImporter.GetCLRTypeName (mappedTypeName.Name.Substring ("ArrayOf".Length)) + "[]";
717 return mappedTypeName.Name;
720 private CodeExpression[] ExportMessages (MessageDescriptionCollection messages, CodeMemberMethod method, bool return_args)
722 CodeExpression [] args = null;
723 foreach (MessageDescription md in messages) {
724 if (md.Direction == MessageDirection.Output) {
725 if (md.Body.ReturnValue != null) {
726 ExportDataContract (md.Body.ReturnValue);
727 method.ReturnType = md.Body.ReturnValue.CodeTypeReference;
733 args = new CodeExpression [md.Body.Parts.Count];
735 MessagePartDescriptionCollection parts = md.Body.Parts;
736 for (int i = 0; i < parts.Count; i++) {
737 ExportDataContract (parts [i]);
739 method.Parameters.Add (
740 new CodeParameterDeclarationExpression (
741 parts [i].CodeTypeReference,
745 args [i] = new CodeArgumentReferenceExpression (parts [i].Name);
755 public CodeTypeReference GenerateServiceEndpoint (
756 ServiceEndpoint endpoint,
757 out ChannelEndpointElement channelElement)
759 throw new NotImplementedException ();
762 void MergeCompileUnit (CodeCompileUnit from, CodeCompileUnit to)
766 foreach (CodeNamespace fns in from.Namespaces) {
768 foreach (CodeNamespace tns in to.Namespaces)
769 if (fns.Name == tns.Name) {
770 // namespaces are merged.
771 MergeNamespace (fns, tns);
776 to.Namespaces.Add (fns);
780 // existing type is skipped.
781 void MergeNamespace (CodeNamespace from, CodeNamespace to)
783 foreach (CodeTypeDeclaration ftd in from.Types) {
785 foreach (CodeTypeDeclaration ttd in to.Types)
786 if (ftd.Name == ttd.Name) {
795 private void ExportDataContract (MessagePartDescription md)
797 if (xsd_data_importer == null)
798 xsd_data_importer = md.Importer;
801 private string GetXmlNamespace (CodeTypeDeclaration type)
803 foreach (CodeAttributeDeclaration attr in type.CustomAttributes) {
804 if (attr.Name == "System.Xml.Serialization.XmlTypeAttribute" ||
805 attr.Name == "System.Xml.Serialization.XmlRootAttribute") {
807 foreach (CodeAttributeArgument arg in attr.Arguments)
808 if (arg.Name == "Namespace")
809 return ((CodePrimitiveExpression)arg.Value).Value as string;
811 //Could not find Namespace arg!