ClientClassGenerator.cs 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Description
  5. {
  6. using System;
  7. using System.CodeDom;
  8. using System.Collections.ObjectModel;
  9. using System.ComponentModel;
  10. using System.Globalization;
  11. using System.Reflection;
  12. using System.Runtime;
  13. using System.ServiceModel;
  14. using System.ServiceModel.Channels;
  15. using System.Threading;
  16. class ClientClassGenerator : IServiceContractGenerationExtension
  17. {
  18. bool tryAddHelperMethod = false;
  19. bool generateEventAsyncMethods = false;
  20. internal ClientClassGenerator(bool tryAddHelperMethod)
  21. : this(tryAddHelperMethod, false)
  22. {
  23. }
  24. internal ClientClassGenerator(bool tryAddHelperMethod, bool generateEventAsyncMethods)
  25. {
  26. this.tryAddHelperMethod = tryAddHelperMethod;
  27. this.generateEventAsyncMethods = generateEventAsyncMethods;
  28. }
  29. static Type clientBaseType = typeof(ClientBase<>);
  30. static Type duplexClientBaseType = typeof(DuplexClientBase<>);
  31. static Type instanceContextType = typeof(InstanceContext);
  32. static Type objectType = typeof(object);
  33. static Type objectArrayType = typeof(object[]);
  34. static Type exceptionType = typeof(Exception);
  35. static Type boolType = typeof(bool);
  36. static Type stringType = typeof(string);
  37. static Type endpointAddressType = typeof(EndpointAddress);
  38. static Type uriType = typeof(Uri);
  39. static Type bindingType = typeof(Binding);
  40. static Type sendOrPostCallbackType = typeof(SendOrPostCallback);
  41. static Type asyncCompletedEventArgsType = typeof(AsyncCompletedEventArgs);
  42. static Type eventHandlerType = typeof(EventHandler<>);
  43. static Type voidType = typeof(void);
  44. static Type asyncResultType = typeof(IAsyncResult);
  45. static Type asyncCallbackType = typeof(AsyncCallback);
  46. static CodeTypeReference voidTypeRef = new CodeTypeReference(typeof(void));
  47. static CodeTypeReference asyncResultTypeRef = new CodeTypeReference(typeof(IAsyncResult));
  48. static string inputInstanceName = "callbackInstance";
  49. static string invokeAsyncCompletedEventArgsTypeName = "InvokeAsyncCompletedEventArgs";
  50. static string invokeAsyncMethodName = "InvokeAsync";
  51. static string raiseExceptionIfNecessaryMethodName = "RaiseExceptionIfNecessary";
  52. static string beginOperationDelegateTypeName = "BeginOperationDelegate";
  53. static string endOperationDelegateTypeName = "EndOperationDelegate";
  54. static string getDefaultValueForInitializationMethodName = "GetDefaultValueForInitialization";
  55. // IMPORTANT: this table tracks the set of .ctors in ClientBase and DuplexClientBase.
  56. // This table must be kept in [....]
  57. // for DuplexClientBase, the initial InstanceContext param is assumed; ctor overloads must match between ClientBase and DuplexClientBase
  58. static Type[][] ClientCtorParamTypes = new Type[][]
  59. {
  60. new Type[] { },
  61. new Type[] { stringType, },
  62. new Type[] { stringType, stringType, },
  63. new Type[] { stringType, endpointAddressType, },
  64. new Type[] { bindingType, endpointAddressType, },
  65. };
  66. static string[][] ClientCtorParamNames = new string[][]
  67. {
  68. new string[] { },
  69. new string[] { "endpointConfigurationName", },
  70. new string[] { "endpointConfigurationName", "remoteAddress", },
  71. new string[] { "endpointConfigurationName", "remoteAddress", },
  72. new string[] { "binding", "remoteAddress", },
  73. };
  74. static Type[] EventArgsCtorParamTypes = new Type[]
  75. {
  76. objectArrayType,
  77. exceptionType,
  78. boolType,
  79. objectType
  80. };
  81. static string[] EventArgsCtorParamNames = new string[]
  82. {
  83. "results",
  84. "exception",
  85. "cancelled",
  86. "userState"
  87. };
  88. static string[] EventArgsPropertyNames = new string[]
  89. {
  90. "Results",
  91. "Error",
  92. "Cancelled",
  93. "UserState"
  94. };
  95. #if DEBUG
  96. static BindingFlags ctorBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
  97. static string DebugCheckTable_errorString = "Client code generation table out of [....] with ClientBase and DuplexClientBase ctors. Please investigate.";
  98. // check the table against what we would get from reflection
  99. static void DebugCheckTable()
  100. {
  101. Fx.Assert(ClientCtorParamNames.Length == ClientCtorParamTypes.Length, DebugCheckTable_errorString);
  102. for (int i = 0; i < ClientCtorParamTypes.Length; i++)
  103. {
  104. DebugCheckTable_ValidateCtor(clientBaseType.GetConstructor(ctorBindingFlags, null, ClientCtorParamTypes[i], null), ClientCtorParamNames[i]);
  105. Type[] duplexCtorTypes1 = DebugCheckTable_InsertAtStart(ClientCtorParamTypes[i], objectType);
  106. Type[] duplexCtorTypes2 = DebugCheckTable_InsertAtStart(ClientCtorParamTypes[i], instanceContextType);
  107. string[] duplexCtorNames = DebugCheckTable_InsertAtStart(ClientCtorParamNames[i], inputInstanceName);
  108. DebugCheckTable_ValidateCtor(duplexClientBaseType.GetConstructor(ctorBindingFlags, null, duplexCtorTypes1, null), duplexCtorNames);
  109. DebugCheckTable_ValidateCtor(duplexClientBaseType.GetConstructor(ctorBindingFlags, null, duplexCtorTypes2, null), duplexCtorNames);
  110. }
  111. // ClientBase<> has extra InstanceContext overloads that we do not call directly from the generated code, but which we
  112. // need to account for in this assert
  113. Fx.Assert(clientBaseType.GetConstructors(ctorBindingFlags).Length == ClientCtorParamTypes.Length * 2, DebugCheckTable_errorString);
  114. // DuplexClientBase<> also has extra object/InstanceContext overloads (but we call these)
  115. Fx.Assert(duplexClientBaseType.GetConstructors(ctorBindingFlags).Length == ClientCtorParamTypes.Length * 2, DebugCheckTable_errorString);
  116. }
  117. static T[] DebugCheckTable_InsertAtStart<T>(T[] arr, T item)
  118. {
  119. T[] newArr = new T[arr.Length + 1];
  120. newArr[0] = item;
  121. Array.Copy(arr, 0, newArr, 1, arr.Length);
  122. return newArr;
  123. }
  124. static void DebugCheckTable_ValidateCtor(ConstructorInfo ctor, string[] paramNames)
  125. {
  126. Fx.Assert(ctor != null, DebugCheckTable_errorString);
  127. ParameterInfo[] parameters = ctor.GetParameters();
  128. Fx.Assert(parameters.Length == paramNames.Length, DebugCheckTable_errorString);
  129. for (int i = 0; i < paramNames.Length; i++)
  130. {
  131. Fx.Assert(parameters[i].Name == paramNames[i], DebugCheckTable_errorString);
  132. }
  133. }
  134. #endif
  135. void IServiceContractGenerationExtension.GenerateContract(ServiceContractGenerationContext context)
  136. {
  137. #if DEBUG
  138. // DebugCheckTable();
  139. #endif
  140. CodeTypeDeclaration clientType = context.TypeFactory.CreateClassType();
  141. // Have to make sure that client name does not match any methods: member names can not be the same as their enclosing type (CSharp only)
  142. clientType.Name = NamingHelper.GetUniqueName(GetClientClassName(context.ContractType.Name), DoesMethodNameExist, context.Operations);
  143. CodeTypeReference contractTypeRef = context.ContractTypeReference;
  144. if (context.DuplexCallbackType == null)
  145. clientType.BaseTypes.Add(new CodeTypeReference(context.ServiceContractGenerator.GetCodeTypeReference(typeof(ClientBase<>)).BaseType, context.ContractTypeReference));
  146. else
  147. clientType.BaseTypes.Add(new CodeTypeReference(context.ServiceContractGenerator.GetCodeTypeReference(typeof(DuplexClientBase<>)).BaseType, context.ContractTypeReference));
  148. clientType.BaseTypes.Add(context.ContractTypeReference);
  149. if (!(ClientCtorParamNames.Length == ClientCtorParamTypes.Length))
  150. {
  151. Fx.Assert("Invalid client generation constructor table initialization");
  152. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid client generation constructor table initialization")));
  153. }
  154. for (int i = 0; i < ClientCtorParamNames.Length; i++)
  155. {
  156. if (!(ClientCtorParamNames[i].Length == ClientCtorParamTypes[i].Length))
  157. {
  158. Fx.Assert("Invalid client generation constructor table initialization");
  159. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid client generation constructor table initialization")));
  160. }
  161. CodeConstructor ctor = new CodeConstructor();
  162. ctor.Attributes = MemberAttributes.Public;
  163. if (context.DuplexCallbackType != null)
  164. {
  165. ctor.Parameters.Add(new CodeParameterDeclarationExpression(typeof(InstanceContext), inputInstanceName));
  166. ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(inputInstanceName));
  167. }
  168. for (int j = 0; j < ClientCtorParamNames[i].Length; j++)
  169. {
  170. ctor.Parameters.Add(new CodeParameterDeclarationExpression(ClientCtorParamTypes[i][j], ClientCtorParamNames[i][j]));
  171. ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(ClientCtorParamNames[i][j]));
  172. }
  173. clientType.Members.Add(ctor);
  174. }
  175. foreach (OperationContractGenerationContext operationContext in context.Operations)
  176. {
  177. // Note that we generate all the client-side methods, even inherited ones.
  178. if (operationContext.Operation.IsServerInitiated()) continue;
  179. CodeTypeReference declaringContractTypeRef = operationContext.DeclaringTypeReference;
  180. GenerateClientClassMethod(clientType, contractTypeRef, operationContext.SyncMethod, this.tryAddHelperMethod, declaringContractTypeRef);
  181. if (operationContext.IsAsync)
  182. {
  183. CodeMemberMethod beginMethod = GenerateClientClassMethod(clientType, contractTypeRef, operationContext.BeginMethod, this.tryAddHelperMethod, declaringContractTypeRef);
  184. CodeMemberMethod endMethod = GenerateClientClassMethod(clientType, contractTypeRef, operationContext.EndMethod, this.tryAddHelperMethod, declaringContractTypeRef);
  185. if (this.generateEventAsyncMethods)
  186. {
  187. GenerateEventAsyncMethods(context, clientType, operationContext.SyncMethod.Name, beginMethod, endMethod);
  188. }
  189. }
  190. if (operationContext.IsTask)
  191. {
  192. GenerateClientClassMethod(clientType, contractTypeRef, operationContext.TaskMethod, !operationContext.Operation.HasOutputParameters && this.tryAddHelperMethod, declaringContractTypeRef);
  193. }
  194. }
  195. context.Namespace.Types.Add(clientType);
  196. context.ClientType = clientType;
  197. context.ClientTypeReference = ServiceContractGenerator.NamespaceHelper.GetCodeTypeReference(context.Namespace, clientType);
  198. }
  199. static CodeMemberMethod GenerateClientClassMethod(CodeTypeDeclaration clientType, CodeTypeReference contractTypeRef, CodeMemberMethod method, bool addHelperMethod, CodeTypeReference declaringContractTypeRef)
  200. {
  201. CodeMemberMethod methodImpl = GetImplementationOfMethod(contractTypeRef, method);
  202. AddMethodImpl(methodImpl);
  203. int methodPosition = clientType.Members.Add(methodImpl);
  204. CodeMemberMethod helperMethod = null;
  205. if (addHelperMethod)
  206. {
  207. helperMethod = GenerateHelperMethod(declaringContractTypeRef, methodImpl);
  208. if (helperMethod != null)
  209. {
  210. clientType.Members[methodPosition].CustomAttributes.Add(CreateEditorBrowsableAttribute(EditorBrowsableState.Advanced));
  211. clientType.Members.Add(helperMethod);
  212. }
  213. }
  214. return (helperMethod != null) ? helperMethod : methodImpl;
  215. }
  216. internal static CodeAttributeDeclaration CreateEditorBrowsableAttribute(EditorBrowsableState editorBrowsableState)
  217. {
  218. CodeAttributeDeclaration browsableAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(EditorBrowsableAttribute)));
  219. CodeTypeReferenceExpression browsableAttributeState = new CodeTypeReferenceExpression(typeof(EditorBrowsableState));
  220. CodeAttributeArgument browsableAttributeValue = new CodeAttributeArgument(new CodeFieldReferenceExpression(browsableAttributeState, editorBrowsableState.ToString()));
  221. browsableAttribute.Arguments.Add(browsableAttributeValue);
  222. return browsableAttribute;
  223. }
  224. private static CodeMemberMethod GenerateHelperMethod(CodeTypeReference ifaceType, CodeMemberMethod method)
  225. {
  226. CodeMemberMethod helperMethod = new CodeMemberMethod();
  227. helperMethod.Name = method.Name;
  228. helperMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  229. CodeMethodInvokeExpression invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeCastExpression(ifaceType, new CodeThisReferenceExpression()), method.Name));
  230. bool hasTypedMessage = false;
  231. foreach (CodeParameterDeclarationExpression param in method.Parameters)
  232. {
  233. CodeTypeDeclaration paramTypeDecl = ServiceContractGenerator.NamespaceHelper.GetCodeType(param.Type);
  234. if (paramTypeDecl != null)
  235. {
  236. hasTypedMessage = true;
  237. CodeVariableReferenceExpression inValue = new CodeVariableReferenceExpression("inValue");
  238. helperMethod.Statements.Add(new CodeVariableDeclarationStatement(param.Type, inValue.VariableName, new CodeObjectCreateExpression(param.Type)));
  239. invokeMethod.Parameters.Add(inValue);
  240. GenerateParameters(helperMethod, paramTypeDecl, inValue, FieldDirection.In);
  241. }
  242. else
  243. {
  244. helperMethod.Parameters.Add(new CodeParameterDeclarationExpression(param.Type, param.Name));
  245. invokeMethod.Parameters.Add(new CodeArgumentReferenceExpression(param.Name));
  246. }
  247. }
  248. if (method.ReturnType.BaseType == voidTypeRef.BaseType)
  249. helperMethod.Statements.Add(invokeMethod);
  250. else
  251. {
  252. CodeTypeDeclaration returnTypeDecl = ServiceContractGenerator.NamespaceHelper.GetCodeType(method.ReturnType);
  253. if (returnTypeDecl != null)
  254. {
  255. hasTypedMessage = true;
  256. CodeVariableReferenceExpression outVar = new CodeVariableReferenceExpression("retVal");
  257. helperMethod.Statements.Add(new CodeVariableDeclarationStatement(method.ReturnType, outVar.VariableName, invokeMethod));
  258. CodeMethodReturnStatement returnStatement = GenerateParameters(helperMethod, returnTypeDecl, outVar, FieldDirection.Out);
  259. if (returnStatement != null)
  260. helperMethod.Statements.Add(returnStatement);
  261. }
  262. else
  263. {
  264. helperMethod.Statements.Add(new CodeMethodReturnStatement(invokeMethod));
  265. helperMethod.ReturnType = method.ReturnType;
  266. }
  267. }
  268. if (hasTypedMessage)
  269. method.PrivateImplementationType = ifaceType;
  270. return hasTypedMessage ? helperMethod : null;
  271. }
  272. private static CodeMethodReturnStatement GenerateParameters(CodeMemberMethod helperMethod, CodeTypeDeclaration codeTypeDeclaration, CodeExpression target, FieldDirection dir)
  273. {
  274. CodeMethodReturnStatement returnStatement = null;
  275. foreach (CodeTypeMember member in codeTypeDeclaration.Members)
  276. {
  277. CodeMemberField field = member as CodeMemberField;
  278. if (field == null)
  279. continue;
  280. CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(target, field.Name);
  281. CodeTypeDeclaration bodyTypeDecl = ServiceContractGenerator.NamespaceHelper.GetCodeType(field.Type);
  282. if (bodyTypeDecl != null)
  283. {
  284. if (dir == FieldDirection.In)
  285. helperMethod.Statements.Add(new CodeAssignStatement(fieldRef, new CodeObjectCreateExpression(field.Type)));
  286. returnStatement = GenerateParameters(helperMethod, bodyTypeDecl, fieldRef, dir);
  287. continue;
  288. }
  289. CodeParameterDeclarationExpression param = GetRefParameter(helperMethod.Parameters, dir, field);
  290. if (param == null && dir == FieldDirection.Out && helperMethod.ReturnType.BaseType == voidTypeRef.BaseType)
  291. {
  292. helperMethod.ReturnType = field.Type;
  293. returnStatement = new CodeMethodReturnStatement(fieldRef);
  294. }
  295. else
  296. {
  297. if (param == null)
  298. {
  299. param = new CodeParameterDeclarationExpression(field.Type, NamingHelper.GetUniqueName(field.Name, DoesParameterNameExist, helperMethod));
  300. param.Direction = dir;
  301. helperMethod.Parameters.Add(param);
  302. }
  303. if (dir == FieldDirection.Out)
  304. helperMethod.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression(param.Name), fieldRef));
  305. else
  306. helperMethod.Statements.Add(new CodeAssignStatement(fieldRef, new CodeArgumentReferenceExpression(param.Name)));
  307. }
  308. }
  309. return returnStatement;
  310. }
  311. private static CodeParameterDeclarationExpression GetRefParameter(CodeParameterDeclarationExpressionCollection parameters, FieldDirection dir, CodeMemberField field)
  312. {
  313. foreach (CodeParameterDeclarationExpression p in parameters)
  314. {
  315. if (p.Name == field.Name)
  316. {
  317. if (p.Direction != dir && p.Type.BaseType == field.Type.BaseType)
  318. {
  319. p.Direction = FieldDirection.Ref;
  320. return p;
  321. }
  322. return null;
  323. }
  324. }
  325. return null;
  326. }
  327. internal static bool DoesMemberNameExist(string name, object typeDeclarationObject)
  328. {
  329. CodeTypeDeclaration typeDeclaration = (CodeTypeDeclaration)typeDeclarationObject;
  330. if (string.Compare(typeDeclaration.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  331. {
  332. return true;
  333. }
  334. foreach (CodeTypeMember member in typeDeclaration.Members)
  335. {
  336. if (string.Compare(member.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  337. {
  338. return true;
  339. }
  340. }
  341. return false;
  342. }
  343. internal static bool DoesTypeNameExists(string name, object codeTypeDeclarationCollectionObject)
  344. {
  345. CodeTypeDeclarationCollection codeTypeDeclarations = (CodeTypeDeclarationCollection)codeTypeDeclarationCollectionObject;
  346. foreach (CodeTypeDeclaration codeTypeDeclaration in codeTypeDeclarations)
  347. {
  348. if (string.Compare(codeTypeDeclaration.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  349. {
  350. return true;
  351. }
  352. }
  353. return false;
  354. }
  355. internal static bool DoesTypeAndMemberNameExist(string name, object nameCollection)
  356. {
  357. object[] nameCollections = (object[])nameCollection;
  358. if (DoesTypeNameExists(name, nameCollections[0]))
  359. {
  360. return true;
  361. }
  362. if (DoesMemberNameExist(name, nameCollections[1]))
  363. {
  364. return true;
  365. }
  366. return false;
  367. }
  368. internal static bool DoesMethodNameExist(string name, object operationsObject)
  369. {
  370. Collection<OperationContractGenerationContext> operations = (Collection<OperationContractGenerationContext>)operationsObject;
  371. foreach (OperationContractGenerationContext operationContext in operations)
  372. {
  373. if (String.Compare(operationContext.SyncMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  374. return true;
  375. if (operationContext.IsAsync)
  376. {
  377. if (String.Compare(operationContext.BeginMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  378. return true;
  379. if (String.Compare(operationContext.EndMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  380. return true;
  381. }
  382. if (operationContext.IsTask)
  383. {
  384. if (String.Compare(operationContext.TaskMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  385. return true;
  386. }
  387. }
  388. return false;
  389. }
  390. internal static bool DoesParameterNameExist(string name, object methodObject)
  391. {
  392. CodeMemberMethod method = (CodeMemberMethod)methodObject;
  393. if (String.Compare(method.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  394. return true;
  395. CodeParameterDeclarationExpressionCollection parameters = method.Parameters;
  396. foreach (CodeParameterDeclarationExpression p in parameters)
  397. {
  398. if (String.Compare(p.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
  399. return true;
  400. }
  401. return false;
  402. }
  403. static void AddMethodImpl(CodeMemberMethod method)
  404. {
  405. CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression(GetChannelReference(), method.Name);
  406. foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
  407. {
  408. methodInvoke.Parameters.Add(new CodeDirectionExpression(parameter.Direction, new CodeVariableReferenceExpression(parameter.Name)));
  409. }
  410. if (IsVoid(method))
  411. method.Statements.Add(methodInvoke);
  412. else
  413. method.Statements.Add(new CodeMethodReturnStatement(methodInvoke));
  414. }
  415. static CodeMemberMethod GetImplementationOfMethod(CodeTypeReference ifaceType, CodeMemberMethod method)
  416. {
  417. CodeMemberMethod m = new CodeMemberMethod();
  418. m.Name = method.Name;
  419. m.ImplementationTypes.Add(ifaceType);
  420. m.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  421. foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
  422. {
  423. CodeParameterDeclarationExpression newParam = new CodeParameterDeclarationExpression(parameter.Type, parameter.Name);
  424. newParam.Direction = parameter.Direction;
  425. m.Parameters.Add(newParam);
  426. }
  427. m.ReturnType = method.ReturnType;
  428. return m;
  429. }
  430. static void GenerateEventAsyncMethods(ServiceContractGenerationContext context, CodeTypeDeclaration clientType,
  431. string syncMethodName, CodeMemberMethod beginMethod, CodeMemberMethod endMethod)
  432. {
  433. CodeTypeDeclaration operationCompletedEventArgsType = CreateOperationCompletedEventArgsType(context, syncMethodName, endMethod);
  434. CodeMemberEvent operationCompletedEvent = CreateOperationCompletedEvent(context, clientType, syncMethodName, operationCompletedEventArgsType);
  435. CodeMemberField beginOperationDelegate = CreateBeginOperationDelegate(context, clientType, syncMethodName);
  436. CodeMemberMethod beginOperationMethod = CreateBeginOperationMethod(context, clientType, syncMethodName, beginMethod);
  437. CodeMemberField endOperationDelegate = CreateEndOperationDelegate(context, clientType, syncMethodName);
  438. CodeMemberMethod endOperationMethod = CreateEndOperationMethod(context, clientType, syncMethodName, endMethod);
  439. CodeMemberField operationCompletedDelegate = CreateOperationCompletedDelegate(context, clientType, syncMethodName);
  440. CodeMemberMethod operationCompletedMethod = CreateOperationCompletedMethod(context, clientType, syncMethodName, operationCompletedEventArgsType, operationCompletedEvent);
  441. CodeMemberMethod eventAsyncMethod = CreateEventAsyncMethod(context, clientType, syncMethodName, beginMethod,
  442. beginOperationDelegate, beginOperationMethod, endOperationDelegate, endOperationMethod, operationCompletedDelegate, operationCompletedMethod);
  443. CreateEventAsyncMethodOverload(clientType, eventAsyncMethod);
  444. // hide the normal async methods from intellisense
  445. beginMethod.CustomAttributes.Add(CreateEditorBrowsableAttribute(EditorBrowsableState.Advanced));
  446. endMethod.CustomAttributes.Add(CreateEditorBrowsableAttribute(EditorBrowsableState.Advanced));
  447. }
  448. static CodeTypeDeclaration CreateOperationCompletedEventArgsType(ServiceContractGenerationContext context,
  449. string syncMethodName, CodeMemberMethod endMethod)
  450. {
  451. if ((endMethod.Parameters.Count == 1) && (endMethod.ReturnType.BaseType == voidTypeRef.BaseType))
  452. {
  453. // no need to create new event args type, use AsyncCompletedEventArgs
  454. return null;
  455. }
  456. CodeTypeDeclaration argsType = context.TypeFactory.CreateClassType();
  457. argsType.BaseTypes.Add(new CodeTypeReference(asyncCompletedEventArgsType));
  458. // define object[] results field.
  459. CodeMemberField resultsField = new CodeMemberField();
  460. resultsField.Type = new CodeTypeReference(objectArrayType);
  461. CodeFieldReferenceExpression resultsFieldReference = new CodeFieldReferenceExpression();
  462. resultsFieldReference.TargetObject = new CodeThisReferenceExpression();
  463. // create constructor, that assigns the results field.
  464. CodeConstructor ctor = new CodeConstructor();
  465. ctor.Attributes = MemberAttributes.Public;
  466. for (int i = 0; i < EventArgsCtorParamTypes.Length; i++)
  467. {
  468. ctor.Parameters.Add(new CodeParameterDeclarationExpression(EventArgsCtorParamTypes[i], EventArgsCtorParamNames[i]));
  469. if (i > 0)
  470. {
  471. ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(EventArgsCtorParamNames[i]));
  472. }
  473. }
  474. argsType.Members.Add(ctor);
  475. ctor.Statements.Add(new CodeAssignStatement(resultsFieldReference, new CodeVariableReferenceExpression(EventArgsCtorParamNames[0])));
  476. // create properties for the out parameters
  477. int asyncResultParamIndex = GetAsyncResultParamIndex(endMethod);
  478. int count = 0;
  479. for (int i = 0; i < endMethod.Parameters.Count; i++)
  480. {
  481. if (i != asyncResultParamIndex)
  482. {
  483. CreateEventAsyncCompletedArgsTypeProperty(argsType,
  484. endMethod.Parameters[i].Type,
  485. endMethod.Parameters[i].Name,
  486. new CodeArrayIndexerExpression(resultsFieldReference, new CodePrimitiveExpression(count++)));
  487. }
  488. }
  489. // create the property for the return type
  490. if (endMethod.ReturnType.BaseType != voidTypeRef.BaseType)
  491. {
  492. CreateEventAsyncCompletedArgsTypeProperty(
  493. argsType,
  494. endMethod.ReturnType,
  495. NamingHelper.GetUniqueName("Result", DoesMemberNameExist, argsType),
  496. new CodeArrayIndexerExpression(resultsFieldReference,
  497. new CodePrimitiveExpression(count)));
  498. }
  499. // Name the "results" field after generating the properties to make sure it does
  500. // not conflict with the property names.
  501. resultsField.Name = NamingHelper.GetUniqueName("results", DoesMemberNameExist, argsType);
  502. resultsFieldReference.FieldName = resultsField.Name;
  503. argsType.Members.Add(resultsField);
  504. // Name the type making sure that it does not conflict with its members and types already present in
  505. // the namespace.
  506. argsType.Name = NamingHelper.GetUniqueName(GetOperationCompletedEventArgsTypeName(syncMethodName),
  507. DoesTypeAndMemberNameExist, new object[] { context.Namespace.Types, argsType });
  508. context.Namespace.Types.Add(argsType);
  509. return argsType;
  510. }
  511. static int GetAsyncResultParamIndex(CodeMemberMethod endMethod)
  512. {
  513. int index = endMethod.Parameters.Count - 1;
  514. if (endMethod.Parameters[index].Type.BaseType != asyncResultTypeRef.BaseType)
  515. {
  516. // workaround for CSD Dev Framework:10826, the unwrapped end method has IAsyncResult as first param.
  517. index = 0;
  518. }
  519. return index;
  520. }
  521. static CodeMemberProperty CreateEventAsyncCompletedArgsTypeProperty(CodeTypeDeclaration ownerTypeDecl,
  522. CodeTypeReference propertyType, string propertyName, CodeExpression propertyValueExpr)
  523. {
  524. CodeMemberProperty property = new CodeMemberProperty();
  525. property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  526. property.Type = propertyType;
  527. property.Name = propertyName;
  528. property.HasSet = false;
  529. property.HasGet = true;
  530. CodeCastExpression castExpr = new CodeCastExpression(propertyType, propertyValueExpr);
  531. CodeMethodReturnStatement returnStmt = new CodeMethodReturnStatement(castExpr);
  532. property.GetStatements.Add(new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), raiseExceptionIfNecessaryMethodName));
  533. property.GetStatements.Add(returnStmt);
  534. ownerTypeDecl.Members.Add(property);
  535. return property;
  536. }
  537. static CodeMemberEvent CreateOperationCompletedEvent(ServiceContractGenerationContext context,
  538. CodeTypeDeclaration clientType, string syncMethodName, CodeTypeDeclaration operationCompletedEventArgsType)
  539. {
  540. CodeMemberEvent operationCompletedEvent = new CodeMemberEvent();
  541. operationCompletedEvent.Attributes = MemberAttributes.Public;
  542. operationCompletedEvent.Type = new CodeTypeReference(eventHandlerType);
  543. if (operationCompletedEventArgsType == null)
  544. {
  545. operationCompletedEvent.Type.TypeArguments.Add(asyncCompletedEventArgsType);
  546. }
  547. else
  548. {
  549. operationCompletedEvent.Type.TypeArguments.Add(operationCompletedEventArgsType.Name);
  550. }
  551. operationCompletedEvent.Name = NamingHelper.GetUniqueName(GetOperationCompletedEventName(syncMethodName),
  552. DoesMethodNameExist, context.Operations);
  553. clientType.Members.Add(operationCompletedEvent);
  554. return operationCompletedEvent;
  555. }
  556. static CodeMemberField CreateBeginOperationDelegate(ServiceContractGenerationContext context,
  557. CodeTypeDeclaration clientType, string syncMethodName)
  558. {
  559. CodeMemberField beginOperationDelegate = new CodeMemberField();
  560. beginOperationDelegate.Attributes = MemberAttributes.Private;
  561. beginOperationDelegate.Type = new CodeTypeReference(beginOperationDelegateTypeName);
  562. beginOperationDelegate.Name = NamingHelper.GetUniqueName(GetBeginOperationDelegateName(syncMethodName),
  563. DoesMethodNameExist, context.Operations);
  564. clientType.Members.Add(beginOperationDelegate);
  565. return beginOperationDelegate;
  566. }
  567. static CodeMemberMethod CreateBeginOperationMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType,
  568. string syncMethodName, CodeMemberMethod beginMethod)
  569. {
  570. CodeMemberMethod onBeginOperationMethod = new CodeMemberMethod();
  571. onBeginOperationMethod.Attributes = MemberAttributes.Private;
  572. onBeginOperationMethod.ReturnType = new CodeTypeReference(asyncResultType);
  573. onBeginOperationMethod.Name = NamingHelper.GetUniqueName(GetBeginOperationMethodName(syncMethodName),
  574. DoesMethodNameExist, context.Operations);
  575. CodeParameterDeclarationExpression inValuesParam = new CodeParameterDeclarationExpression();
  576. inValuesParam.Type = new CodeTypeReference(objectArrayType);
  577. inValuesParam.Name = NamingHelper.GetUniqueName("inValues", DoesParameterNameExist, beginMethod);
  578. onBeginOperationMethod.Parameters.Add(inValuesParam);
  579. CodeMethodInvokeExpression invokeBegin = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), beginMethod.Name);
  580. CodeExpression inValuesRef = new CodeVariableReferenceExpression(inValuesParam.Name);
  581. for (int i = 0; i < beginMethod.Parameters.Count - 2; i++)
  582. {
  583. CodeVariableDeclarationStatement variableDecl = new CodeVariableDeclarationStatement();
  584. variableDecl.Type = beginMethod.Parameters[i].Type;
  585. variableDecl.Name = beginMethod.Parameters[i].Name;
  586. variableDecl.InitExpression = new CodeCastExpression(variableDecl.Type,
  587. new CodeArrayIndexerExpression(inValuesRef, new CodePrimitiveExpression(i)));
  588. onBeginOperationMethod.Statements.Add(variableDecl);
  589. invokeBegin.Parameters.Add(new CodeDirectionExpression(beginMethod.Parameters[i].Direction,
  590. new CodeVariableReferenceExpression(variableDecl.Name)));
  591. }
  592. for (int i = beginMethod.Parameters.Count - 2; i < beginMethod.Parameters.Count; i++)
  593. {
  594. onBeginOperationMethod.Parameters.Add(new CodeParameterDeclarationExpression(
  595. beginMethod.Parameters[i].Type, beginMethod.Parameters[i].Name));
  596. invokeBegin.Parameters.Add(new CodeVariableReferenceExpression(beginMethod.Parameters[i].Name));
  597. }
  598. onBeginOperationMethod.Statements.Add(new CodeMethodReturnStatement(invokeBegin));
  599. clientType.Members.Add(onBeginOperationMethod);
  600. return onBeginOperationMethod;
  601. }
  602. static CodeMemberField CreateEndOperationDelegate(ServiceContractGenerationContext context,
  603. CodeTypeDeclaration clientType, string syncMethodName)
  604. {
  605. CodeMemberField endOperationDelegate = new CodeMemberField();
  606. endOperationDelegate.Attributes = MemberAttributes.Private;
  607. endOperationDelegate.Type = new CodeTypeReference(endOperationDelegateTypeName);
  608. endOperationDelegate.Name = NamingHelper.GetUniqueName(GetEndOperationDelegateName(syncMethodName),
  609. DoesMethodNameExist, context.Operations);
  610. clientType.Members.Add(endOperationDelegate);
  611. return endOperationDelegate;
  612. }
  613. static CodeMemberMethod CreateEndOperationMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType, string syncMethodName, CodeMemberMethod endMethod)
  614. {
  615. CodeMemberMethod onEndOperationMethod = new CodeMemberMethod();
  616. onEndOperationMethod.Attributes = MemberAttributes.Private;
  617. onEndOperationMethod.ReturnType = new CodeTypeReference(objectArrayType);
  618. onEndOperationMethod.Name = NamingHelper.GetUniqueName(GetEndOperationMethodName(syncMethodName), DoesMethodNameExist, context.Operations);
  619. int asyncResultParamIndex = GetAsyncResultParamIndex(endMethod);
  620. CodeMethodInvokeExpression invokeEnd = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), endMethod.Name);
  621. CodeArrayCreateExpression retArray = new CodeArrayCreateExpression();
  622. retArray.CreateType = new CodeTypeReference(objectArrayType);
  623. for (int i = 0; i < endMethod.Parameters.Count; i++)
  624. {
  625. if (i == asyncResultParamIndex)
  626. {
  627. onEndOperationMethod.Parameters.Add(new CodeParameterDeclarationExpression(
  628. endMethod.Parameters[i].Type, endMethod.Parameters[i].Name));
  629. invokeEnd.Parameters.Add(new CodeVariableReferenceExpression(endMethod.Parameters[i].Name));
  630. }
  631. else
  632. {
  633. CodeVariableDeclarationStatement variableDecl = new CodeVariableDeclarationStatement(
  634. endMethod.Parameters[i].Type, endMethod.Parameters[i].Name);
  635. CodeMethodReferenceExpression getDefaultValueMethodRef = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), getDefaultValueForInitializationMethodName, endMethod.Parameters[i].Type);
  636. variableDecl.InitExpression = new CodeMethodInvokeExpression(getDefaultValueMethodRef);
  637. onEndOperationMethod.Statements.Add(variableDecl);
  638. invokeEnd.Parameters.Add(new CodeDirectionExpression(endMethod.Parameters[i].Direction,
  639. new CodeVariableReferenceExpression(variableDecl.Name)));
  640. retArray.Initializers.Add(new CodeVariableReferenceExpression(variableDecl.Name));
  641. }
  642. }
  643. if (endMethod.ReturnType.BaseType != voidTypeRef.BaseType)
  644. {
  645. CodeVariableDeclarationStatement retValDecl = new CodeVariableDeclarationStatement();
  646. retValDecl.Type = endMethod.ReturnType;
  647. retValDecl.Name = NamingHelper.GetUniqueName("retVal", DoesParameterNameExist, endMethod);
  648. retValDecl.InitExpression = invokeEnd;
  649. retArray.Initializers.Add(new CodeVariableReferenceExpression(retValDecl.Name));
  650. onEndOperationMethod.Statements.Add(retValDecl);
  651. }
  652. else
  653. {
  654. onEndOperationMethod.Statements.Add(invokeEnd);
  655. }
  656. if (retArray.Initializers.Count > 0)
  657. {
  658. onEndOperationMethod.Statements.Add(new CodeMethodReturnStatement(retArray));
  659. }
  660. else
  661. {
  662. onEndOperationMethod.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(null)));
  663. }
  664. clientType.Members.Add(onEndOperationMethod);
  665. return onEndOperationMethod;
  666. }
  667. static CodeMemberField CreateOperationCompletedDelegate(ServiceContractGenerationContext context,
  668. CodeTypeDeclaration clientType, string syncMethodName)
  669. {
  670. CodeMemberField operationCompletedDelegate = new CodeMemberField();
  671. operationCompletedDelegate.Attributes = MemberAttributes.Private;
  672. operationCompletedDelegate.Type = new CodeTypeReference(sendOrPostCallbackType);
  673. operationCompletedDelegate.Name = NamingHelper.GetUniqueName(GetOperationCompletedDelegateName(syncMethodName),
  674. DoesMethodNameExist, context.Operations);
  675. clientType.Members.Add(operationCompletedDelegate);
  676. return operationCompletedDelegate;
  677. }
  678. static CodeMemberMethod CreateOperationCompletedMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType,
  679. string syncMethodName, CodeTypeDeclaration operationCompletedEventArgsType, CodeMemberEvent operationCompletedEvent)
  680. {
  681. CodeMemberMethod operationCompletedMethod = new CodeMemberMethod();
  682. operationCompletedMethod.Attributes = MemberAttributes.Private;
  683. operationCompletedMethod.Name = NamingHelper.GetUniqueName(GetOperationCompletedMethodName(syncMethodName),
  684. DoesMethodNameExist, context.Operations);
  685. operationCompletedMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(objectType), "state"));
  686. operationCompletedMethod.ReturnType = new CodeTypeReference(voidType);
  687. CodeVariableDeclarationStatement eventArgsDecl =
  688. new CodeVariableDeclarationStatement(invokeAsyncCompletedEventArgsTypeName, "e");
  689. eventArgsDecl.InitExpression = new CodeCastExpression(invokeAsyncCompletedEventArgsTypeName,
  690. new CodeArgumentReferenceExpression(operationCompletedMethod.Parameters[0].Name));
  691. CodeObjectCreateExpression newEventArgsExpr;
  692. CodeVariableReferenceExpression eventArgsRef = new CodeVariableReferenceExpression(eventArgsDecl.Name);
  693. if (operationCompletedEventArgsType != null)
  694. {
  695. newEventArgsExpr = new CodeObjectCreateExpression(operationCompletedEventArgsType.Name,
  696. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[0]),
  697. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[1]),
  698. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[2]),
  699. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[3]));
  700. }
  701. else
  702. {
  703. newEventArgsExpr = new CodeObjectCreateExpression(asyncCompletedEventArgsType,
  704. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[1]),
  705. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[2]),
  706. new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[3]));
  707. }
  708. CodeEventReferenceExpression completedEvent = new CodeEventReferenceExpression(new CodeThisReferenceExpression(), operationCompletedEvent.Name);
  709. CodeDelegateInvokeExpression raiseEventExpr = new CodeDelegateInvokeExpression(
  710. completedEvent,
  711. new CodeThisReferenceExpression(),
  712. newEventArgsExpr);
  713. CodeConditionStatement ifEventHandlerNotNullBlock = new CodeConditionStatement(
  714. new CodeBinaryOperatorExpression(
  715. completedEvent,
  716. CodeBinaryOperatorType.IdentityInequality,
  717. new CodePrimitiveExpression(null)),
  718. eventArgsDecl,
  719. new CodeExpressionStatement(raiseEventExpr));
  720. operationCompletedMethod.Statements.Add(ifEventHandlerNotNullBlock);
  721. clientType.Members.Add(operationCompletedMethod);
  722. return operationCompletedMethod;
  723. }
  724. static CodeMemberMethod CreateEventAsyncMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType,
  725. string syncMethodName, CodeMemberMethod beginMethod,
  726. CodeMemberField beginOperationDelegate, CodeMemberMethod beginOperationMethod,
  727. CodeMemberField endOperationDelegate, CodeMemberMethod endOperationMethod,
  728. CodeMemberField operationCompletedDelegate, CodeMemberMethod operationCompletedMethod)
  729. {
  730. CodeMemberMethod eventAsyncMethod = new CodeMemberMethod();
  731. eventAsyncMethod.Name = NamingHelper.GetUniqueName(GetEventAsyncMethodName(syncMethodName),
  732. DoesMethodNameExist, context.Operations);
  733. eventAsyncMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  734. eventAsyncMethod.ReturnType = new CodeTypeReference(voidType);
  735. CodeArrayCreateExpression invokeAsyncInValues = new CodeArrayCreateExpression(new CodeTypeReference(objectArrayType));
  736. for (int i = 0; i < beginMethod.Parameters.Count - 2; i++)
  737. {
  738. CodeParameterDeclarationExpression beginMethodParameter = beginMethod.Parameters[i];
  739. CodeParameterDeclarationExpression eventAsyncMethodParameter = new CodeParameterDeclarationExpression(
  740. beginMethodParameter.Type, beginMethodParameter.Name);
  741. eventAsyncMethodParameter.Direction = FieldDirection.In;
  742. eventAsyncMethod.Parameters.Add(eventAsyncMethodParameter);
  743. invokeAsyncInValues.Initializers.Add(new CodeVariableReferenceExpression(eventAsyncMethodParameter.Name));
  744. }
  745. string userStateParamName = NamingHelper.GetUniqueName("userState", DoesParameterNameExist, eventAsyncMethod);
  746. eventAsyncMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(objectType), userStateParamName));
  747. eventAsyncMethod.Statements.Add(CreateDelegateIfNotNull(beginOperationDelegate, beginOperationMethod));
  748. eventAsyncMethod.Statements.Add(CreateDelegateIfNotNull(endOperationDelegate, endOperationMethod));
  749. eventAsyncMethod.Statements.Add(CreateDelegateIfNotNull(operationCompletedDelegate, operationCompletedMethod));
  750. CodeMethodInvokeExpression invokeAsync = new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), invokeAsyncMethodName);
  751. invokeAsync.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), beginOperationDelegate.Name));
  752. if (invokeAsyncInValues.Initializers.Count > 0)
  753. {
  754. invokeAsync.Parameters.Add(invokeAsyncInValues);
  755. }
  756. else
  757. {
  758. invokeAsync.Parameters.Add(new CodePrimitiveExpression(null));
  759. }
  760. invokeAsync.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), endOperationDelegate.Name));
  761. invokeAsync.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), operationCompletedDelegate.Name));
  762. invokeAsync.Parameters.Add(new CodeVariableReferenceExpression(userStateParamName));
  763. eventAsyncMethod.Statements.Add(new CodeExpressionStatement(invokeAsync));
  764. clientType.Members.Add(eventAsyncMethod);
  765. return eventAsyncMethod;
  766. }
  767. static CodeMemberMethod CreateEventAsyncMethodOverload(CodeTypeDeclaration clientType, CodeMemberMethod eventAsyncMethod)
  768. {
  769. CodeMemberMethod eventAsyncMethodOverload = new CodeMemberMethod();
  770. eventAsyncMethodOverload.Attributes = eventAsyncMethod.Attributes;
  771. eventAsyncMethodOverload.Name = eventAsyncMethod.Name;
  772. eventAsyncMethodOverload.ReturnType = eventAsyncMethod.ReturnType;
  773. CodeMethodInvokeExpression invokeEventAsyncMethod = new CodeMethodInvokeExpression(
  774. new CodeThisReferenceExpression(), eventAsyncMethod.Name);
  775. for (int i = 0; i < eventAsyncMethod.Parameters.Count - 1; i++)
  776. {
  777. eventAsyncMethodOverload.Parameters.Add(new CodeParameterDeclarationExpression(
  778. eventAsyncMethod.Parameters[i].Type,
  779. eventAsyncMethod.Parameters[i].Name));
  780. invokeEventAsyncMethod.Parameters.Add(new CodeVariableReferenceExpression(
  781. eventAsyncMethod.Parameters[i].Name));
  782. }
  783. invokeEventAsyncMethod.Parameters.Add(new CodePrimitiveExpression(null));
  784. eventAsyncMethodOverload.Statements.Add(invokeEventAsyncMethod);
  785. int eventAsyncMethodPosition = clientType.Members.IndexOf(eventAsyncMethod);
  786. Fx.Assert(eventAsyncMethodPosition != -1,
  787. "The eventAsyncMethod must be added to the clientType before calling CreateEventAsyncMethodOverload");
  788. clientType.Members.Insert(eventAsyncMethodPosition, eventAsyncMethodOverload);
  789. return eventAsyncMethodOverload;
  790. }
  791. static CodeStatement CreateDelegateIfNotNull(CodeMemberField delegateField, CodeMemberMethod delegateMethod)
  792. {
  793. return new CodeConditionStatement(
  794. new CodeBinaryOperatorExpression(
  795. new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), delegateField.Name),
  796. CodeBinaryOperatorType.IdentityEquality,
  797. new CodePrimitiveExpression(null)),
  798. new CodeAssignStatement(
  799. new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), delegateField.Name),
  800. new CodeDelegateCreateExpression(delegateField.Type,
  801. new CodeThisReferenceExpression(), delegateMethod.Name)));
  802. }
  803. static string GetClassName(string interfaceName)
  804. {
  805. // maybe strip a leading 'I'
  806. if (interfaceName.Length >= 2 &&
  807. String.Compare(interfaceName, 0, Strings.InterfaceTypePrefix, 0, Strings.InterfaceTypePrefix.Length, StringComparison.Ordinal) == 0 &&
  808. Char.IsUpper(interfaceName, 1))
  809. return interfaceName.Substring(1);
  810. else
  811. return interfaceName;
  812. }
  813. static string GetEventAsyncMethodName(string syncMethodName)
  814. {
  815. return string.Format(CultureInfo.InvariantCulture, "{0}Async", syncMethodName);
  816. }
  817. static string GetBeginOperationDelegateName(string syncMethodName)
  818. {
  819. return string.Format(CultureInfo.InvariantCulture, "onBegin{0}Delegate", syncMethodName);
  820. }
  821. static string GetBeginOperationMethodName(string syncMethodName)
  822. {
  823. return string.Format(CultureInfo.InvariantCulture, "OnBegin{0}", syncMethodName);
  824. }
  825. static string GetEndOperationDelegateName(string syncMethodName)
  826. {
  827. return string.Format(CultureInfo.InvariantCulture, "onEnd{0}Delegate", syncMethodName);
  828. }
  829. static string GetEndOperationMethodName(string syncMethodName)
  830. {
  831. return string.Format(CultureInfo.InvariantCulture, "OnEnd{0}", syncMethodName);
  832. }
  833. static string GetOperationCompletedDelegateName(string syncMethodName)
  834. {
  835. return string.Format(CultureInfo.InvariantCulture, "on{0}CompletedDelegate", syncMethodName);
  836. }
  837. static string GetOperationCompletedMethodName(string syncMethodName)
  838. {
  839. return string.Format(CultureInfo.InvariantCulture, "On{0}Completed", syncMethodName);
  840. }
  841. static string GetOperationCompletedEventName(string syncMethodName)
  842. {
  843. return string.Format(CultureInfo.InvariantCulture, "{0}Completed", syncMethodName);
  844. }
  845. static string GetOperationCompletedEventArgsTypeName(string syncMethodName)
  846. {
  847. return string.Format(CultureInfo.InvariantCulture, "{0}CompletedEventArgs", syncMethodName);
  848. }
  849. static internal string GetClientClassName(string interfaceName)
  850. {
  851. return GetClassName(interfaceName) + Strings.ClientTypeSuffix;
  852. }
  853. static bool IsVoid(CodeMemberMethod method)
  854. {
  855. return method.ReturnType == null || String.Compare(method.ReturnType.BaseType, typeof(void).FullName, StringComparison.Ordinal) == 0;
  856. }
  857. static CodeExpression GetChannelReference()
  858. {
  859. return new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), Strings.ClientBaseChannelProperty);
  860. }
  861. static class Strings
  862. {
  863. public const string ClientBaseChannelProperty = "Channel";
  864. public const string ClientTypeSuffix = "Client";
  865. public const string InterfaceTypePrefix = "I";
  866. }
  867. }
  868. }