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 #if USE_DATA_CONTRACT_IMPORTER
66 XsdDataContractImporter xsd_data_importer;
69 public ServiceContractGenerator ()
74 public ServiceContractGenerator (CodeCompileUnit ccu)
79 public ServiceContractGenerator (ConfigurationType config)
84 public ServiceContractGenerator (CodeCompileUnit ccu, ConfigurationType config)
87 this.ccu = new CodeCompileUnit ();
91 Options |= ServiceContractGenerationOptions.ChannelInterface |
92 ServiceContractGenerationOptions.ClientClass;
95 public ConfigurationType Configuration {
96 get { return config; }
99 public Collection<MetadataConversionError> Errors {
100 get { return errors; }
103 public Dictionary<string,string> NamespaceMappings {
104 get { return nsmappings; }
107 public ServiceContractGenerationOptions Options {
108 get { return options; }
109 set { options = value; }
113 get { return GenerateEventBasedAsync || (options & ServiceContractGenerationOptions.AsynchronousMethods) != 0; }
116 bool GenerateEventBasedAsync {
117 get { return (options & ServiceContractGenerationOptions.EventBasedAsynchronousMethods) != 0; }
120 public Dictionary<ContractDescription,Type> ReferencedTypes {
121 get { return referenced_types; }
124 public CodeCompileUnit TargetCompileUnit {
129 public void GenerateBinding (Binding binding,
130 out string bindingSectionName,
131 out string configurationName)
133 throw new NotImplementedException ();
136 #region Service Contract Type
138 // Those implementation classes are very likely to be split
139 // into different classes.
142 public CodeTypeReference GenerateServiceContractType (
143 ContractDescription contractDescription)
145 CodeNamespace cns = GetNamespace (contractDescription.Namespace);
146 imported_names = new Dictionary<QName, QName> ();
147 var ret = ExportInterface (contractDescription, cns);
149 // FIXME: handle duplex callback
151 if ((Options & ServiceContractGenerationOptions.ChannelInterface) != 0)
152 GenerateChannelInterface (contractDescription, cns);
154 if ((Options & ServiceContractGenerationOptions.ClientClass) != 0)
155 GenerateProxyClass (contractDescription, cns);
157 #if USE_DATA_CONTRACT_IMPORTER
158 if (xsd_data_importer != null)
159 MergeCompileUnit (xsd_data_importer.CodeCompileUnit, ccu);
162 // Process extensions. Class first, then methods.
163 // (built-in ones must present before processing class extensions).
164 foreach (var cb in contractDescription.Behaviors) {
165 var gex = cb as IServiceContractGenerationExtension;
167 gex.GenerateContract (contract_context);
169 foreach (var opair in operation_contexts)
170 opair.Key.GenerateOperation (opair.Value);
175 CodeNamespace GetNamespace (string ns)
179 foreach (CodeNamespace cns in ccu.Namespaces)
182 CodeNamespace ncns = new CodeNamespace ();
184 ccu.Namespaces.Add (ncns);
188 CodeTypeDeclaration GetTypeDeclaration (CodeNamespace cns, string name)
190 foreach (CodeTypeDeclaration type in cns.Types)
191 if (type.Name == name)
196 void GenerateProxyClass (ContractDescription cd, CodeNamespace cns)
198 string name = cd.Name + "Client";
200 name = name.Substring (1);
201 CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
203 return; // already imported
204 CodeTypeReference clientBase = new CodeTypeReference (typeof (ClientBase<>));
205 clientBase.TypeArguments.Add (new CodeTypeReference (cd.Name));
206 type = new CodeTypeDeclaration (name);
207 cns.Types.Add (type);
208 type.TypeAttributes = TypeAttributes.Public;
209 type.BaseTypes.Add (clientBase);
210 type.BaseTypes.Add (new CodeTypeReference (cd.Name));
213 CodeConstructor ctor = new CodeConstructor ();
214 ctor.Attributes = MemberAttributes.Public;
215 type.Members.Add (ctor);
217 // .ctor(string endpointConfigurationName)
218 ctor = new CodeConstructor ();
219 ctor.Attributes = MemberAttributes.Public;
220 ctor.Parameters.Add (
221 new CodeParameterDeclarationExpression (
222 new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
223 ctor.BaseConstructorArgs.Add (
224 new CodeArgumentReferenceExpression ("endpointConfigurationName"));
225 type.Members.Add (ctor);
227 // .ctor(string endpointConfigurationName, string remoteAddress)
228 ctor = new CodeConstructor ();
229 ctor.Attributes = MemberAttributes.Public;
230 ctor.Parameters.Add (
231 new CodeParameterDeclarationExpression (
232 new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
233 ctor.Parameters.Add (
234 new CodeParameterDeclarationExpression (
235 new CodeTypeReference (typeof (string)), "remoteAddress"));
236 ctor.BaseConstructorArgs.Add (
237 new CodeArgumentReferenceExpression ("endpointConfigurationName"));
238 ctor.BaseConstructorArgs.Add (
239 new CodeArgumentReferenceExpression ("remoteAddress"));
240 type.Members.Add (ctor);
242 // .ctor(string endpointConfigurationName, EndpointAddress remoteAddress)
243 ctor = new CodeConstructor ();
244 ctor.Attributes = MemberAttributes.Public;
245 ctor.Parameters.Add (
246 new CodeParameterDeclarationExpression (
247 new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
248 ctor.Parameters.Add (
249 new CodeParameterDeclarationExpression (
250 new CodeTypeReference (typeof (EndpointAddress)), "remoteAddress"));
251 ctor.BaseConstructorArgs.Add (
252 new CodeArgumentReferenceExpression ("endpointConfigurationName"));
253 ctor.BaseConstructorArgs.Add (
254 new CodeArgumentReferenceExpression ("remoteAddress"));
255 type.Members.Add (ctor);
257 // .ctor(Binding,EndpointAddress)
258 ctor = new CodeConstructor ();
259 ctor.Attributes = MemberAttributes.Public;
260 ctor.Parameters.Add (
261 new CodeParameterDeclarationExpression (
262 new CodeTypeReference (typeof (Binding)), "binding"));
263 ctor.Parameters.Add (
264 new CodeParameterDeclarationExpression (
265 new CodeTypeReference (typeof (EndpointAddress)), "endpoint"));
266 ctor.BaseConstructorArgs.Add (
267 new CodeArgumentReferenceExpression ("binding"));
268 ctor.BaseConstructorArgs.Add (
269 new CodeArgumentReferenceExpression ("endpoint"));
270 type.Members.Add (ctor);
272 // service contract methods
273 AddImplementationClientMethods (type, cd);
275 if (GenerateEventBasedAsync)
276 foreach (var od in cd.Operations)
277 GenerateEventBasedAsyncSupport (type, od, cns);
280 void GenerateChannelInterface (ContractDescription cd, CodeNamespace cns)
282 string name = cd.Name + "Channel";
283 CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
287 type = new CodeTypeDeclaration ();
289 type.TypeAttributes = TypeAttributes.Interface | TypeAttributes.Public;
290 cns.Types.Add (type);
292 type.BaseTypes.Add (ExportInterface (cd, cns));
293 type.BaseTypes.Add (new CodeTypeReference (typeof (System.ServiceModel.IClientChannel)));
296 CodeTypeReference ExportInterface (ContractDescription cd, CodeNamespace cns)
298 CodeTypeDeclaration type = GetTypeDeclaration (cns, cd.Name);
300 return new CodeTypeReference (type.Name);
301 type = new CodeTypeDeclaration ();
302 type.TypeAttributes = TypeAttributes.Interface;
303 type.TypeAttributes |= TypeAttributes.Public;
304 cns.Types.Add (type);
306 CodeAttributeDeclaration ad =
307 new CodeAttributeDeclaration (
308 new CodeTypeReference (
309 typeof (ServiceContractAttribute)));
310 ad.Arguments.Add (new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (cd.Namespace)));
311 type.CustomAttributes.Add (ad);
312 contract_context = new ServiceContractGenerationContext (this, cd, type);
314 AddOperationMethods (type, cd);
316 return new CodeTypeReference (type.Name);
319 void AddBeginAsyncArgs (CodeMemberMethod cm)
321 var acb = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback");
322 cm.Parameters.Add (acb);
323 var us = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState");
324 cm.Parameters.Add (us);
327 void AddOperationMethods (CodeTypeDeclaration type, ContractDescription cd)
329 foreach (OperationDescription od in cd.Operations) {
330 CodeMemberMethod syncMethod = null, beginMethod = null, endMethod = null;
332 CodeTypeReference returnTypeFromMessageContract = null;
333 syncMethod = GenerateOperationMethod (type, cd, od, false, out returnTypeFromMessageContract);
334 type.Members.Add (syncMethod);
337 beginMethod = GenerateOperationMethod (type, cd, od, true, out returnTypeFromMessageContract);
338 type.Members.Add (beginMethod);
340 var cm = new CodeMemberMethod ();
341 type.Members.Add (cm);
342 cm.Name = "End" + od.Name;
345 var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
346 cm.Parameters.Add (res);
348 if (od.SyncMethod != null) // FIXME: it depends on sync method!
349 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
351 cm.ReturnType = returnTypeFromMessageContract;
354 foreach (var ob in od.Behaviors) {
355 var gex = ob as IOperationContractGenerationExtension;
357 operation_contexts.Add (new OPair (gex, new OperationContractGenerationContext (this, contract_context, od, type, syncMethod, beginMethod, endMethod)));
362 CodeMemberMethod GenerateOperationMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnType)
364 CodeMemberMethod cm = new CodeMemberMethod ();
367 cm.Name = "Begin" + od.Name;
371 if (od.SyncMethod != null) {
372 ExportParameters (cm, od.SyncMethod.GetParameters ());
374 AddBeginAsyncArgs (cm);
375 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
378 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
379 returnType = new CodeTypeReference (od.SyncMethod.ReturnType);
381 ExportMessages (od.Messages, cm, false);
382 returnType = cm.ReturnType;
384 AddBeginAsyncArgs (cm);
385 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
389 // [OperationContract (Action = "...", ReplyAction = "..")]
390 var ad = new CodeAttributeDeclaration (new CodeTypeReference (typeof (OperationContractAttribute)));
391 foreach (MessageDescription md in od.Messages) {
393 ad.Arguments.Add (new CodeAttributeArgument ("Action", new CodePrimitiveExpression (md.Action)));
395 ad.Arguments.Add (new CodeAttributeArgument ("ReplyAction", new CodePrimitiveExpression (md.Action)));
398 ad.Arguments.Add (new CodeAttributeArgument ("AsyncPattern", new CodePrimitiveExpression (true)));
399 cm.CustomAttributes.Add (ad);
404 void ExportParameters (CodeMemberMethod method, ParameterInfo [] parameters)
406 foreach (ParameterInfo pi in parameters)
407 method.Parameters.Add (
408 new CodeParameterDeclarationExpression (
409 new CodeTypeReference (pi.ParameterType),
413 void AddImplementationClientMethods (CodeTypeDeclaration type, ContractDescription cd)
415 foreach (OperationDescription od in cd.Operations) {
417 CodeTypeReference returnTypeFromMessageContract = null;
418 cm = GenerateImplementationClientMethod (type, cd, od, false, out returnTypeFromMessageContract);
419 type.Members.Add (cm);
424 cm = GenerateImplementationClientMethod (type, cd, od, true, out returnTypeFromMessageContract);
425 type.Members.Add (cm);
427 // EndXxx() implementation
429 cm = new CodeMemberMethod ();
430 cm.Attributes = MemberAttributes.Public
431 | MemberAttributes.Final;
432 type.Members.Add (cm);
433 cm.Name = "End" + od.Name;
435 var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
436 cm.Parameters.Add (res);
438 if (od.SyncMethod != null) // FIXME: it depends on sync method!
439 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
441 cm.ReturnType = returnTypeFromMessageContract;
443 string resultArgName = "result";
444 if (od.EndMethod != null)
445 resultArgName = od.EndMethod.GetParameters () [0].Name;
447 var call = new CodeMethodInvokeExpression (
448 new CodePropertyReferenceExpression (
449 new CodeBaseReferenceExpression (),
452 new CodeArgumentReferenceExpression (resultArgName));
454 if (cm.ReturnType.BaseType == "System.Void")
455 cm.Statements.Add (new CodeExpressionStatement (call));
457 cm.Statements.Add (new CodeMethodReturnStatement (call));
461 CodeMemberMethod GenerateImplementationClientMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnTypeFromMessageContract)
463 CodeMemberMethod cm = new CodeMemberMethod ();
465 cm.Name = "Begin" + od.Name;
468 cm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
469 returnTypeFromMessageContract = null;
471 List<CodeExpression> args = new List<CodeExpression> ();
472 if (od.SyncMethod != null) {
473 ParameterInfo [] pars = od.SyncMethod.GetParameters ();
474 ExportParameters (cm, pars);
475 cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
477 foreach (ParameterInfo pi in pars)
478 args.Add (new CodeArgumentReferenceExpression (pi.Name));
480 args.AddRange (ExportMessages (od.Messages, cm, true));
481 returnTypeFromMessageContract = cm.ReturnType;
483 AddBeginAsyncArgs (cm);
484 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
488 args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
489 args.Add (new CodeArgumentReferenceExpression ("userState"));
492 CodeExpression call = new CodeMethodInvokeExpression (
493 new CodePropertyReferenceExpression (
494 new CodeBaseReferenceExpression (),
499 if (cm.ReturnType.BaseType == "System.Void")
500 cm.Statements.Add (new CodeExpressionStatement (call));
502 cm.Statements.Add (new CodeMethodReturnStatement (call));
506 CodeMemberMethod FindByName (CodeTypeDeclaration type, string name)
508 foreach (var m in type.Members) {
509 var method = m as CodeMemberMethod;
510 if (method != null && method.Name == name)
516 void GenerateEventBasedAsyncSupport (CodeTypeDeclaration type, OperationDescription od, CodeNamespace cns)
518 var method = FindByName (type, od.Name) ?? FindByName (type, "Begin" + od.Name);
519 var endMethod = method.Name == od.Name ? null : FindByName (type, "End" + od.Name);
520 bool methodAsync = method.Name.StartsWith ("Begin", StringComparison.Ordinal);
522 var thisExpr = new CodeThisReferenceExpression ();
523 var baseExpr = new CodeBaseReferenceExpression ();
524 var nullExpr = new CodePrimitiveExpression (null);
525 var asyncResultType = new CodeTypeReference (typeof (IAsyncResult));
527 // OnBeginXxx() implementation
528 var cm = new CodeMemberMethod () {
529 Name = "OnBegin" + od.Name,
530 Attributes = MemberAttributes.Private | MemberAttributes.Final,
531 ReturnType = asyncResultType
533 type.Members.Add (cm);
535 AddMethodParam (cm, typeof (object []), "args");
536 AddMethodParam (cm, typeof (AsyncCallback), "asyncCallback");
537 AddMethodParam (cm, typeof (object), "userState");
539 var call = new CodeMethodInvokeExpression (
542 for (int idx = 0; idx < method.Parameters.Count - (methodAsync ? 2 : 0); idx++) {
543 var p = method.Parameters [idx];
544 cm.Statements.Add (new CodeVariableDeclarationStatement (p.Type, p.Name, new CodeCastExpression (p.Type, new CodeArrayIndexerExpression (new CodeArgumentReferenceExpression ("args"), new CodePrimitiveExpression (idx)))));
545 call.Parameters.Add (new CodeVariableReferenceExpression (p.Name));
547 call.Parameters.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
548 call.Parameters.Add (new CodeArgumentReferenceExpression ("userState"));
549 cm.Statements.Add (new CodeMethodReturnStatement (call));
551 // OnEndXxx() implementation
552 cm = new CodeMemberMethod () {
553 Name = "OnEnd" + od.Name,
554 Attributes = MemberAttributes.Private | MemberAttributes.Final,
555 ReturnType = new CodeTypeReference (typeof (object [])) };
556 type.Members.Add (cm);
558 AddMethodParam (cm, typeof (IAsyncResult), "result");
560 var outArgRefs = new List<CodeVariableReferenceExpression> ();
562 for (int idx = 0; idx < method.Parameters.Count; idx++) {
563 var p = method.Parameters [idx];
564 if (p.Direction != FieldDirection.In) {
565 cm.Statements.Add (new CodeVariableDeclarationStatement (p.Type, p.Name));
566 outArgRefs.Add (new CodeVariableReferenceExpression (p.Name)); // FIXME: should this work? They need "out" or "ref" modifiers.
570 call = new CodeMethodInvokeExpression (
573 new CodeArgumentReferenceExpression ("result"));
574 call.Parameters.AddRange (outArgRefs.Cast<CodeExpression> ().ToArray ()); // questionable
576 cm.Statements.Add (new CodeVariableDeclarationStatement (typeof (object), "__ret", call));
577 var retCreate = new CodeArrayCreateExpression (typeof (object));
578 retCreate.Initializers.Add (new CodeVariableReferenceExpression ("__ret"));
579 foreach (var outArgRef in outArgRefs)
580 retCreate.Initializers.Add (new CodeVariableReferenceExpression (outArgRef.VariableName));
582 cm.Statements.Add (new CodeMethodReturnStatement (retCreate));
584 // OnXxxCompleted() implementation
585 cm = new CodeMemberMethod () {
586 Name = "On" + od.Name + "Completed",
587 Attributes = MemberAttributes.Private | MemberAttributes.Final };
588 type.Members.Add (cm);
590 AddMethodParam (cm, typeof (object), "state");
592 var iaargs = new CodeTypeReference ("InvokeAsyncCompletedEventArgs"); // avoid messy System.Type instance for generic nested type :|
593 var iaref = new CodeVariableReferenceExpression ("args");
594 var methodEventArgs = new CodeObjectCreateExpression (new CodeTypeReference (od.Name + "CompletedEventArgs"),
595 new CodePropertyReferenceExpression (iaref, "Results"),
596 new CodePropertyReferenceExpression (iaref, "Error"),
597 new CodePropertyReferenceExpression (iaref, "Cancelled"),
598 new CodePropertyReferenceExpression (iaref, "UserState"));
599 cm.Statements.Add (new CodeConditionStatement (
600 new CodeBinaryOperatorExpression (
601 new CodeEventReferenceExpression (thisExpr, od.Name + "Completed"), CodeBinaryOperatorType.IdentityInequality, nullExpr),
602 new CodeVariableDeclarationStatement (iaargs, "args", new CodeCastExpression (iaargs, new CodeArgumentReferenceExpression ("state"))),
603 new CodeExpressionStatement (new CodeMethodInvokeExpression (thisExpr, od.Name + "Completed", thisExpr, methodEventArgs))));
606 type.Members.Add (new CodeMemberField (new CodeTypeReference ("BeginOperationDelegate"), "onBegin" + od.Name + "Delegate"));
607 type.Members.Add (new CodeMemberField (new CodeTypeReference ("EndOperationDelegate"), "onEnd" + od.Name + "Delegate"));
608 type.Members.Add (new CodeMemberField (new CodeTypeReference (typeof (SendOrPostCallback)), "on" + od.Name + "CompletedDelegate"));
610 // XxxCompletedEventArgs class
611 var argsType = new CodeTypeDeclaration (od.Name + "CompletedEventArgs");
612 argsType.BaseTypes.Add (new CodeTypeReference (typeof (AsyncCompletedEventArgs)));
613 cns.Types.Add (argsType);
615 var argsCtor = new CodeConstructor () {
616 Attributes = MemberAttributes.Public | MemberAttributes.Final };
617 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object []), "results"));
618 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (Exception), "error"));
619 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (bool), "cancelled"));
620 argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
621 argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("error"));
622 argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("cancelled"));
623 argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("userState"));
624 var resultsField = new CodeFieldReferenceExpression (thisExpr, "results");
625 argsCtor.Statements.Add (new CodeAssignStatement (resultsField, new CodeArgumentReferenceExpression ("results")));
626 argsType.Members.Add (argsCtor);
628 argsType.Members.Add (new CodeMemberField (typeof (object []), "results"));
630 var resultProp = new CodeMemberProperty {
632 Type = endMethod != null ? endMethod.ReturnType : method.ReturnType,
633 Attributes = MemberAttributes.Public | MemberAttributes.Final };
634 resultProp.GetStatements.Add (new CodeMethodReturnStatement (new CodeCastExpression (resultProp.Type, new CodeArrayIndexerExpression (resultsField, new CodePrimitiveExpression (0)))));
635 argsType.Members.Add (resultProp);
638 var handlerType = new CodeTypeReference (typeof (EventHandler<>));
639 handlerType.TypeArguments.Add (new CodeTypeReference (argsType.Name));
640 type.Members.Add (new CodeMemberEvent () {
641 Name = od.Name + "Completed",
643 Attributes = MemberAttributes.Public | MemberAttributes.Final });
645 // XxxAsync() implementations
646 bool hasAsync = false;
647 foreach (int __x in Enumerable.Range (0, 2)) {
648 cm = new CodeMemberMethod ();
649 type.Members.Add (cm);
650 cm.Name = od.Name + "Async";
651 cm.Attributes = MemberAttributes.Public
652 | MemberAttributes.Final;
654 var inArgs = new List<CodeParameterDeclarationExpression > ();
656 for (int idx = 0; idx < method.Parameters.Count - (methodAsync ? 2 : 0); idx++) {
657 var pd = method.Parameters [idx];
659 cm.Parameters.Add (pd);
662 // First one is overload without asyncState arg.
664 call = new CodeMethodInvokeExpression (thisExpr, cm.Name, inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ());
665 call.Parameters.Add (nullExpr);
666 cm.Statements.Add (new CodeExpressionStatement (call));
671 // Second one is the primary one.
673 cm.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
675 // if (onBeginBarOperDelegate == null) onBeginBarOperDelegate = new BeginOperationDelegate (OnBeginBarOper);
676 // if (onEndBarOperDelegate == null) onEndBarOperDelegate = new EndOperationDelegate (OnEndBarOper);
677 // if (onBarOperCompletedDelegate == null) onBarOperCompletedDelegate = new BeginOperationDelegate (OnBarOperCompleted);
678 var beginOperDelegateRef = new CodeFieldReferenceExpression (thisExpr, "onBegin" + od.Name + "Delegate");
679 var endOperDelegateRef = new CodeFieldReferenceExpression (thisExpr, "onEnd" + od.Name + "Delegate");
680 var operCompletedDelegateRef = new CodeFieldReferenceExpression (thisExpr, "on" + od.Name + "CompletedDelegate");
682 var ifstmt = new CodeConditionStatement (
683 new CodeBinaryOperatorExpression (beginOperDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
684 new CodeAssignStatement (beginOperDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference ("BeginOperationDelegate"), thisExpr, "OnBegin" + od.Name)));
685 cm.Statements.Add (ifstmt);
686 ifstmt = new CodeConditionStatement (
687 new CodeBinaryOperatorExpression (endOperDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
688 new CodeAssignStatement (endOperDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference ("EndOperationDelegate"), thisExpr, "OnEnd" + od.Name)));
689 cm.Statements.Add (ifstmt);
690 ifstmt = new CodeConditionStatement (
691 new CodeBinaryOperatorExpression (operCompletedDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
692 new CodeAssignStatement (operCompletedDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference (typeof (SendOrPostCallback)), thisExpr, "On" + od.Name + "Completed")));
693 cm.Statements.Add (ifstmt);
695 // InvokeAsync (onBeginBarOperDelegate, inValues, onEndBarOperDelegate, onBarOperCompletedDelegate, userState);
697 inArgs.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
699 var args = new List<CodeExpression> ();
700 args.Add (beginOperDelegateRef);
701 args.Add (new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
702 args.Add (endOperDelegateRef);
703 args.Add (new CodeFieldReferenceExpression (thisExpr, "on" + od.Name + "CompletedDelegate"));
704 args.Add (new CodeArgumentReferenceExpression ("userState"));
705 call = new CodeMethodInvokeExpression (baseExpr, "InvokeAsync", args.ToArray ());
706 cm.Statements.Add (new CodeExpressionStatement (call));
710 void AddMethodParam (CodeMemberMethod cm, Type type, string name)
712 cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (type), name));
715 const string ms_arrays_ns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
717 string GetCodeTypeName (QName mappedTypeName)
719 if (mappedTypeName.Namespace == ms_arrays_ns)
720 return DataContractSerializerMessageContractImporter.GetCLRTypeName (mappedTypeName.Name.Substring ("ArrayOf".Length)) + "[]";
721 return mappedTypeName.Name;
724 private CodeExpression[] ExportMessages (MessageDescriptionCollection messages, CodeMemberMethod method, bool return_args)
726 CodeExpression [] args = null;
727 foreach (MessageDescription md in messages) {
729 if (md.Body.ReturnValue != null) {
730 ExportDataContract (md.Body.ReturnValue);
731 #if USE_DATA_CONTRACT_IMPORTER
732 method.ReturnType = md.Body.ReturnValue.CodeTypeReference;
734 method.ReturnType = new CodeTypeReference (GetCodeTypeName (md.Body.ReturnValue.TypeName));
741 args = new CodeExpression [md.Body.Parts.Count];
743 MessagePartDescriptionCollection parts = md.Body.Parts;
744 for (int i = 0; i < parts.Count; i++) {
745 ExportDataContract (parts [i]);
747 method.Parameters.Add (
748 new CodeParameterDeclarationExpression (
749 #if USE_DATA_CONTRACT_IMPORTER
750 parts [i].CodeTypeReference,
752 new CodeTypeReference (GetCodeTypeName (parts [i].TypeName)),
757 args [i] = new CodeArgumentReferenceExpression (parts [i].Name);
767 public CodeTypeReference GenerateServiceEndpoint (
768 ServiceEndpoint endpoint,
769 out ChannelEndpointElement channelElement)
771 throw new NotImplementedException ();
774 #if USE_DATA_CONTRACT_IMPORTER
775 void MergeCompileUnit (CodeCompileUnit from, CodeCompileUnit to)
779 foreach (CodeNamespace fns in from.Namespaces) {
781 foreach (CodeNamespace tns in to.Namespaces)
782 if (fns.Name == tns.Name) {
783 // namespaces are merged.
784 MergeNamespace (fns, tns);
789 to.Namespaces.Add (fns);
793 // existing type is skipped.
794 void MergeNamespace (CodeNamespace from, CodeNamespace to)
796 foreach (CodeTypeDeclaration ftd in from.Types) {
798 foreach (CodeTypeDeclaration ttd in to.Types)
799 if (ftd.Name == ttd.Name) {
809 private void ExportDataContract (MessagePartDescription md)
811 #if USE_DATA_CONTRACT_IMPORTER
812 if (xsd_data_importer == null)
813 xsd_data_importer = md.Importer;
815 var mapping = md.XmlTypeMapping;
820 QName qname = new QName (mapping.TypeName, mapping.Namespace);
821 if (imported_names.ContainsKey (qname))
824 CodeNamespace cns = new CodeNamespace ();
826 XmlCodeExporter xce = new XmlCodeExporter (cns);
827 xce.ExportTypeMapping (mapping);
829 List <CodeTypeDeclaration> to_remove = new List <CodeTypeDeclaration> ();
831 //Process the types just generated
832 //FIXME: Iterate and assign the types to correct namespaces
833 //At the end, add all those namespaces to the ccu
834 foreach (CodeTypeDeclaration type in cns.Types) {
835 string ns = GetXmlNamespace (type);
837 //FIXME: do what here?
840 QName type_name = new QName (type.Name, ns);
841 if (imported_names.ContainsKey (type_name)) {
842 //Type got reemitted, so remove it!
843 to_remove.Add (type);
846 if (ns == ms_arrays_ns) {
847 //Do not emit arrays as an independent type.
848 to_remove.Add (type);
852 imported_names [type_name] = type_name;
854 type.Comments.Clear ();
856 type.CustomAttributes.Clear ();
861 type.CustomAttributes.Add (
862 new CodeAttributeDeclaration (
863 new CodeTypeReference ("System.CodeDom.Compiler.GeneratedCodeAttribute"),
864 new CodeAttributeArgument (new CodePrimitiveExpression ("System.Runtime.Serialization")),
865 new CodeAttributeArgument (new CodePrimitiveExpression ("3.0.0.0"))));
867 type.CustomAttributes.Add (
868 new CodeAttributeDeclaration (
869 new CodeTypeReference ("System.Runtime.Serialization.DataContractAttribute")));
871 //BaseType and interface
872 type.BaseTypes.Add (new CodeTypeReference (typeof (object)));
873 type.BaseTypes.Add (new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject"));
875 foreach (CodeTypeMember mbr in type.Members) {
876 CodeMemberProperty p = mbr as CodeMemberProperty;
880 if ((p.Attributes & MemberAttributes.Public) == MemberAttributes.Public) {
881 //FIXME: Clear all attributes or only XmlElementAttribute?
882 p.CustomAttributes.Clear ();
883 p.CustomAttributes.Add (new CodeAttributeDeclaration (
884 new CodeTypeReference ("System.Runtime.Serialization.DataMemberAttribute")));
891 CodeMemberField field = new CodeMemberField (
892 new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject"),
893 "extensionDataField");
894 field.Attributes = MemberAttributes.Private | MemberAttributes.Final;
895 type.Members.Add (field);
898 CodeMemberProperty prop = new CodeMemberProperty ();
899 prop.Type = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
900 prop.Name = "ExtensionData";
901 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
904 prop.GetStatements.Add (new CodeMethodReturnStatement (
905 new CodeFieldReferenceExpression (
906 new CodeThisReferenceExpression (),
907 "extensionDataField")));
910 prop.SetStatements.Add (new CodeAssignStatement (
911 new CodeFieldReferenceExpression (
912 new CodeThisReferenceExpression (),
913 "extensionDataField"),
914 new CodePropertySetValueReferenceExpression ()));
916 type.Members.Add (prop);
919 foreach (CodeTypeDeclaration type in to_remove)
920 cns.Types.Remove (type);
922 ccu.Namespaces.Add (cns);
926 private string GetXmlNamespace (CodeTypeDeclaration type)
928 foreach (CodeAttributeDeclaration attr in type.CustomAttributes) {
929 if (attr.Name == "System.Xml.Serialization.XmlTypeAttribute" ||
930 attr.Name == "System.Xml.Serialization.XmlRootAttribute") {
932 foreach (CodeAttributeArgument arg in attr.Arguments)
933 if (arg.Name == "Namespace")
934 return ((CodePrimitiveExpression)arg.Value).Value as string;
936 //Could not find Namespace arg!