ProtocolImporter.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. //
  2. // System.Web.Services.Description.ProtocolImporter.cs
  3. //
  4. // Author:
  5. // Tim Coleman ([email protected])
  6. // Lluis Sanchez Gual ([email protected])
  7. //
  8. // Copyright (C) Tim Coleman, 2002
  9. //
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System;
  31. using System.CodeDom;
  32. using System.CodeDom.Compiler;
  33. using System.Web.Services;
  34. using System.Web.Services.Protocols;
  35. using System.Xml.Serialization;
  36. using System.Xml;
  37. using System.Xml.Schema;
  38. using System.Collections;
  39. using System.Configuration;
  40. namespace System.Web.Services.Description {
  41. public abstract class ProtocolImporter {
  42. #region Fields
  43. Binding binding;
  44. string className;
  45. CodeIdentifiers classNames;
  46. CodeNamespace codeNamespace;
  47. CodeTypeDeclaration codeTypeDeclaration;
  48. Message inputMessage;
  49. string methodName;
  50. Operation operation;
  51. OperationBinding operationBinding;
  52. Message outputMessage;
  53. Port port;
  54. PortType portType;
  55. Service service;
  56. ServiceDescriptionImportWarnings warnings = (ServiceDescriptionImportWarnings)0;
  57. ServiceDescriptionImporter descriptionImporter;
  58. ImportInfo iinfo;
  59. XmlSchemas xmlSchemas;
  60. XmlSchemas soapSchemas;
  61. #if NET_2_0
  62. ArrayList asyncTypes = new ArrayList ();
  63. #endif
  64. #endregion // Fields
  65. #region Constructors
  66. protected ProtocolImporter ()
  67. {
  68. }
  69. #endregion // Constructors
  70. #region Properties
  71. [MonoTODO]
  72. public XmlSchemas AbstractSchemas {
  73. get { return descriptionImporter.Schemas; }
  74. }
  75. public Binding Binding {
  76. get { return binding; }
  77. }
  78. public string ClassName {
  79. get { return className; }
  80. }
  81. public CodeIdentifiers ClassNames {
  82. get { return classNames; }
  83. }
  84. public CodeNamespace CodeNamespace {
  85. get { return codeNamespace; }
  86. }
  87. public CodeTypeDeclaration CodeTypeDeclaration {
  88. get { return codeTypeDeclaration; }
  89. }
  90. [MonoTODO]
  91. public XmlSchemas ConcreteSchemas {
  92. get { return descriptionImporter.Schemas; }
  93. }
  94. public Message InputMessage {
  95. get { return inputMessage; }
  96. }
  97. public string MethodName {
  98. get { return methodName; }
  99. }
  100. public Operation Operation {
  101. get { return operation; }
  102. }
  103. public OperationBinding OperationBinding {
  104. get { return operationBinding; }
  105. }
  106. public Message OutputMessage {
  107. get { return outputMessage; }
  108. }
  109. public Port Port {
  110. get { return port; }
  111. }
  112. public PortType PortType {
  113. get { return portType; }
  114. }
  115. public abstract string ProtocolName {
  116. get;
  117. }
  118. public XmlSchemas Schemas {
  119. get { return descriptionImporter.Schemas; }
  120. }
  121. public Service Service {
  122. get { return service; }
  123. }
  124. public ServiceDescriptionCollection ServiceDescriptions {
  125. get { return descriptionImporter.ServiceDescriptions; }
  126. }
  127. public ServiceDescriptionImportStyle Style {
  128. get { return descriptionImporter.Style; }
  129. }
  130. public ServiceDescriptionImportWarnings Warnings {
  131. get { return warnings; }
  132. set { warnings = value; }
  133. }
  134. internal ImportInfo ImportInfo
  135. {
  136. get { return iinfo; }
  137. }
  138. internal XmlSchemas LiteralSchemas
  139. {
  140. get { return xmlSchemas; }
  141. }
  142. internal XmlSchemas EncodedSchemas
  143. {
  144. get { return soapSchemas; }
  145. }
  146. #if NET_2_0
  147. internal CodeGenerationOptions CodeGenerationOptions {
  148. get { return descriptionImporter.CodeGenerationOptions; }
  149. }
  150. internal CodeDomProvider CodeGenerator {
  151. get { return descriptionImporter.CodeGenerator; }
  152. }
  153. internal ImportContext ImportContext {
  154. get { return descriptionImporter.Context; }
  155. }
  156. #endif
  157. #endregion // Properties
  158. #region Methods
  159. internal bool Import (ServiceDescriptionImporter descriptionImporter, CodeNamespace codeNamespace, ArrayList importInfo)
  160. {
  161. this.descriptionImporter = descriptionImporter;
  162. this.classNames = new CodeIdentifiers();;
  163. this.codeNamespace = codeNamespace;
  164. warnings = (ServiceDescriptionImportWarnings) 0;
  165. bool found = false;
  166. ClasifySchemas (importInfo);
  167. BeginNamespace ();
  168. foreach (ImportInfo info in importInfo)
  169. {
  170. foreach (Service service in info.ServiceDescription.Services)
  171. {
  172. this.service = service;
  173. int bindingCount = 0;
  174. foreach (Port port in service.Ports)
  175. {
  176. binding = ServiceDescriptions.GetBinding (port.Binding);
  177. if (IsBindingSupported ()) bindingCount ++;
  178. }
  179. foreach (Port port in service.Ports)
  180. {
  181. this.iinfo = info;
  182. this.port = port;
  183. binding = ServiceDescriptions.GetBinding (port.Binding);
  184. if (!IsBindingSupported ()) continue;
  185. found = true;
  186. ImportPortBinding (bindingCount > 1);
  187. }
  188. }
  189. }
  190. if (!found)
  191. {
  192. // Looks like MS.NET generates classes for all bindings if
  193. // no services are present
  194. foreach (ImportInfo info in importInfo)
  195. {
  196. this.iinfo = info;
  197. foreach (Binding b in info.ServiceDescription.Bindings)
  198. {
  199. this.binding = b;
  200. this.service = null;
  201. this.port = null;
  202. if (!IsBindingSupported ()) continue;
  203. found = true;
  204. ImportPortBinding (true);
  205. }
  206. }
  207. }
  208. EndNamespace ();
  209. if (!found) warnings = ServiceDescriptionImportWarnings.NoCodeGenerated;
  210. return found;
  211. }
  212. void ImportPortBinding (bool multipleBindings)
  213. {
  214. if (port != null) {
  215. if (multipleBindings) className = binding.Name;
  216. else className = service.Name;
  217. }
  218. else
  219. className = binding.Name;
  220. className = classNames.AddUnique (CodeIdentifier.MakeValid (className), port);
  221. className = className.Replace ("_x0020_", ""); // MS.NET seems to do this
  222. try
  223. {
  224. portType = ServiceDescriptions.GetPortType (binding.Type);
  225. if (portType == null) throw new Exception ("Port type not found: " + binding.Type);
  226. CodeTypeDeclaration codeClass = BeginClass ();
  227. codeTypeDeclaration = codeClass;
  228. AddCodeType (codeClass, port != null ? port.Documentation : null);
  229. codeClass.Attributes = MemberAttributes.Public;
  230. if (service != null && service.Documentation != null && service.Documentation != "")
  231. AddComments (codeClass, service.Documentation);
  232. if (Style == ServiceDescriptionImportStyle.Client) {
  233. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Diagnostics.DebuggerStepThroughAttribute");
  234. AddCustomAttribute (codeClass, att, true);
  235. att = new CodeAttributeDeclaration ("System.ComponentModel.DesignerCategoryAttribute");
  236. att.Arguments.Add (GetArg ("code"));
  237. AddCustomAttribute (codeClass, att, true);
  238. }
  239. else
  240. codeClass.TypeAttributes = System.Reflection.TypeAttributes.Abstract | System.Reflection.TypeAttributes.Public;
  241. if (binding.Operations.Count == 0) {
  242. warnings |= ServiceDescriptionImportWarnings.NoMethodsGenerated;
  243. return;
  244. }
  245. foreach (OperationBinding oper in binding.Operations)
  246. {
  247. operationBinding = oper;
  248. operation = FindPortOperation ();
  249. if (operation == null)
  250. throw new Exception ("Operation " + operationBinding.Name + " not found in portType " + PortType.Name);
  251. inputMessage = null;
  252. outputMessage = null;
  253. foreach (OperationMessage omsg in operation.Messages)
  254. {
  255. Message msg = ServiceDescriptions.GetMessage (omsg.Message);
  256. if (msg == null) throw new Exception ("Message not found: " + omsg.Message);
  257. if (omsg is OperationInput)
  258. inputMessage = msg;
  259. else
  260. outputMessage = msg;
  261. }
  262. CodeMemberMethod method = GenerateMethod ();
  263. if (method != null)
  264. {
  265. methodName = method.Name;
  266. if (operation.Documentation != null && operation.Documentation != "")
  267. AddComments (method, operation.Documentation);
  268. #if NET_2_0
  269. if (Style == ServiceDescriptionImportStyle.Client)
  270. AddAsyncMembers (method.Name, method);
  271. #endif
  272. }
  273. }
  274. #if NET_2_0
  275. if (Style == ServiceDescriptionImportStyle.Client)
  276. AddAsyncTypes ();
  277. #endif
  278. EndClass ();
  279. }
  280. catch (InvalidOperationException ex)
  281. {
  282. warnings |= ServiceDescriptionImportWarnings.NoCodeGenerated;
  283. UnsupportedBindingWarning (ex.Message);
  284. }
  285. }
  286. Operation FindPortOperation ()
  287. {
  288. string inMessage = null;
  289. string outMessage = null;
  290. int numMsg = 1;
  291. if (operationBinding.Input == null) throw new InvalidOperationException ("Input operation binding not found");
  292. inMessage = (operationBinding.Input.Name != null) ? operationBinding.Input.Name : operationBinding.Name;
  293. if (operationBinding.Output != null) {
  294. outMessage = (operationBinding.Output.Name != null) ? operationBinding.Output.Name : operationBinding.Name;
  295. numMsg++;
  296. }
  297. string operName = operationBinding.Name;
  298. Operation foundOper = null;
  299. foreach (Operation oper in PortType.Operations)
  300. {
  301. if (oper.Name == operName)
  302. {
  303. int hits = 0;
  304. foreach (OperationMessage omsg in oper.Messages)
  305. {
  306. if (omsg is OperationInput && GetOperMessageName (omsg, operName) == inMessage) hits++;
  307. if (omsg is OperationOutput && GetOperMessageName (omsg, operName) == outMessage) hits++;
  308. }
  309. if (hits == numMsg) return oper;
  310. foundOper = oper;
  311. }
  312. }
  313. return foundOper;
  314. }
  315. string GetOperMessageName (OperationMessage msg, string operName)
  316. {
  317. if (msg.Name == null) return operName;
  318. else return msg.Name;
  319. }
  320. internal void GenerateServiceUrl (string location, CodeStatementCollection stms)
  321. {
  322. if (ImportInfo.AppSettingUrlKey == null || ImportInfo.AppSettingUrlKey == string.Empty) {
  323. if (location != null) {
  324. CodeExpression ce = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), "Url");
  325. CodeAssignStatement cas = new CodeAssignStatement (ce, new CodePrimitiveExpression (location));
  326. stms.Add (cas);
  327. }
  328. }
  329. else
  330. {
  331. CodeExpression prop = new CodePropertyReferenceExpression (new CodeTypeReferenceExpression ("System.Configuration.ConfigurationSettings"), "AppSettings");
  332. prop = new CodeIndexerExpression (prop, new CodePrimitiveExpression (ImportInfo.AppSettingUrlKey));
  333. stms.Add (new CodeVariableDeclarationStatement (typeof(string), "urlSetting", prop));
  334. CodeExpression urlSetting = new CodeVariableReferenceExpression ("urlSetting");
  335. CodeExpression thisUrl = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), "Url");
  336. CodeStatement[] trueStms = new CodeStatement [1];
  337. CodeExpression ce = urlSetting;
  338. CodeExpression cond = new CodeBinaryOperatorExpression (urlSetting, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
  339. if (ImportInfo.AppSettingBaseUrl != null)
  340. ce = new CodeMethodInvokeExpression (new CodeTypeReferenceExpression (typeof(string)), "Concat", ce, new CodePrimitiveExpression (ImportInfo.AppSettingBaseUrl));
  341. trueStms [0] = new CodeAssignStatement (thisUrl, ce);
  342. if (location != null) {
  343. CodeStatement[] falseStms = new CodeStatement [1];
  344. falseStms [0] = new CodeAssignStatement (thisUrl, new CodePrimitiveExpression (location));
  345. stms.Add (new CodeConditionStatement (cond, trueStms, falseStms));
  346. }
  347. else
  348. stms.Add (new CodeConditionStatement (cond, trueStms));
  349. }
  350. }
  351. void ClasifySchemas (ArrayList importInfo)
  352. {
  353. // I don't like this, but I could not find any other way of clasifying
  354. // schemas between encoded and literal.
  355. xmlSchemas = new XmlSchemas ();
  356. soapSchemas = new XmlSchemas ();
  357. foreach (ImportInfo info in importInfo)
  358. {
  359. foreach (Service service in info.ServiceDescription.Services)
  360. {
  361. foreach (Port port in service.Ports)
  362. {
  363. this.iinfo = info;
  364. this.port = port;
  365. binding = ServiceDescriptions.GetBinding (port.Binding);
  366. if (binding == null) continue;
  367. portType = ServiceDescriptions.GetPortType (binding.Type);
  368. if (portType == null) continue;
  369. foreach (OperationBinding oper in binding.Operations)
  370. {
  371. operationBinding = oper;
  372. operation = FindPortOperation ();
  373. if (operation == null) continue;
  374. foreach (OperationMessage omsg in operation.Messages)
  375. {
  376. Message msg = ServiceDescriptions.GetMessage (omsg.Message);
  377. if (msg == null) continue;
  378. if (omsg is OperationInput)
  379. inputMessage = msg;
  380. else
  381. outputMessage = msg;
  382. }
  383. if (GetMessageEncoding (oper.Input) == SoapBindingUse.Encoded)
  384. AddMessageSchema (soapSchemas, oper.Input, inputMessage);
  385. else
  386. AddMessageSchema (xmlSchemas, oper.Input, inputMessage);
  387. if (oper.Output != null) {
  388. if (GetMessageEncoding (oper.Output) == SoapBindingUse.Encoded)
  389. AddMessageSchema (soapSchemas, oper.Output, outputMessage);
  390. else
  391. AddMessageSchema (xmlSchemas, oper.Output, outputMessage);
  392. }
  393. }
  394. }
  395. }
  396. }
  397. XmlSchemas defaultList = xmlSchemas;
  398. if (xmlSchemas.Count == 0 && soapSchemas.Count > 0)
  399. defaultList = soapSchemas;
  400. // Schemas not referenced by any message
  401. foreach (XmlSchema sc in Schemas)
  402. {
  403. if (!soapSchemas.Contains (sc) && !xmlSchemas.Contains (sc)) {
  404. if (ImportsEncodedNamespace (sc))
  405. soapSchemas.Add (sc);
  406. else
  407. defaultList.Add (sc);
  408. }
  409. }
  410. }
  411. void AddMessageSchema (XmlSchemas schemas, MessageBinding mb, Message msg)
  412. {
  413. foreach (MessagePart part in msg.Parts)
  414. {
  415. if (part.Element != XmlQualifiedName.Empty)
  416. AddIncludingSchema (schemas, part.Element.Namespace);
  417. else if (part.Type != XmlQualifiedName.Empty)
  418. AddIncludingSchema (schemas, part.Type.Namespace);
  419. }
  420. SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
  421. if (sbb != null) AddIncludingSchema (schemas, sbb.Namespace);
  422. }
  423. void AddIncludingSchema (XmlSchemas list, string ns)
  424. {
  425. XmlSchema sc = Schemas [ns];
  426. if (sc == null || list.Contains (sc)) return;
  427. list.Add (sc);
  428. foreach (XmlSchemaObject ob in sc.Includes)
  429. {
  430. XmlSchemaImport import = ob as XmlSchemaImport;
  431. if (import != null) AddIncludingSchema (list, import.Namespace);
  432. }
  433. }
  434. SoapBindingUse GetMessageEncoding (MessageBinding mb)
  435. {
  436. SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
  437. if (sbb == null)
  438. {
  439. if (mb is InputBinding) return SoapBindingUse.Encoded;
  440. else return SoapBindingUse.Literal;
  441. }
  442. else
  443. if (sbb.Use == SoapBindingUse.Encoded) return SoapBindingUse.Encoded;
  444. else
  445. return SoapBindingUse.Literal;
  446. }
  447. bool ImportsEncodedNamespace (XmlSchema sc)
  448. {
  449. foreach (XmlSchemaObject ob in sc.Includes)
  450. {
  451. XmlSchemaImport import = ob as XmlSchemaImport;
  452. if (import == null)
  453. continue;
  454. #if NET_2_0
  455. if (import.Namespace == Soap11BindingExtensionReflector.EncodingNamespace
  456. || import.Namespace == Soap12BindingExtensionReflector.EncodingNamespace)
  457. #else
  458. if (import.Namespace == Soap11BindingExtensionReflector.EncodingNamespace)
  459. #endif
  460. return true;
  461. }
  462. return false;
  463. }
  464. #if NET_2_0
  465. void AddAsyncTypes ()
  466. {
  467. foreach (CodeTypeDeclaration type in asyncTypes)
  468. codeNamespace.Types.Add (type);
  469. asyncTypes.Clear ();
  470. }
  471. void AddAsyncMembers (string messageName, CodeMemberMethod method)
  472. {
  473. CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
  474. CodePrimitiveExpression enull = new CodePrimitiveExpression (null);
  475. CodeMemberField codeField = new CodeMemberField (typeof(System.Threading.SendOrPostCallback), messageName + "OperationCompleted");
  476. codeField.Attributes = MemberAttributes.Private;
  477. CodeTypeDeclaration.Members.Add (codeField);
  478. // Event arguments class
  479. string argsClassName = classNames.AddUnique (messageName + "CompletedEventArgs", null);
  480. CodeTypeDeclaration argsClass = new CodeTypeDeclaration (argsClassName);
  481. argsClass.BaseTypes.Add (new CodeTypeReference ("System.ComponentModel.AsyncCompletedEventArgs"));
  482. CodeMemberField resultsField = new CodeMemberField (typeof(object[]), "results");
  483. resultsField.Attributes = MemberAttributes.Private;
  484. argsClass.Members.Add (resultsField);
  485. CodeConstructor cc = new CodeConstructor ();
  486. cc.Attributes = MemberAttributes.Assembly;
  487. cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object[]), "results"));
  488. cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(System.Exception), "exception"));
  489. cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(bool), "cancelled"));
  490. cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "userState"));
  491. cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("exception"));
  492. cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("cancelled"));
  493. cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("userState"));
  494. CodeExpression thisResults = new CodeFieldReferenceExpression (ethis, "results");
  495. cc.Statements.Add (new CodeAssignStatement (thisResults, new CodeVariableReferenceExpression ("results")));
  496. argsClass.Members.Add (cc);
  497. int ind = 0;
  498. if (method.ReturnType.BaseType != "System.Void")
  499. argsClass.Members.Add (CreateArgsProperty (method.ReturnType, "Result", ind++));
  500. foreach (CodeParameterDeclarationExpression par in method.Parameters)
  501. {
  502. if (par.Direction == FieldDirection.Out || par.Direction == FieldDirection.Ref)
  503. argsClass.Members.Add (CreateArgsProperty (par.Type, par.Name, ind++));
  504. }
  505. bool needsArgsClass = (ind > 0);
  506. if (needsArgsClass)
  507. asyncTypes.Add (argsClass);
  508. else
  509. argsClassName = "System.ComponentModel.AsyncCompletedEventArgs";
  510. // Event delegate type
  511. CodeTypeDelegate delegateType = new CodeTypeDelegate (messageName + "CompletedEventHandler");
  512. delegateType.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "sender"));
  513. delegateType.Parameters.Add (new CodeParameterDeclarationExpression (argsClassName, "args"));
  514. // Event member
  515. CodeMemberEvent codeEvent = new CodeMemberEvent ();
  516. codeEvent.Name = messageName + "Completed";
  517. codeEvent.Type = new CodeTypeReference (delegateType.Name);
  518. CodeTypeDeclaration.Members.Add (codeEvent);
  519. // Async method (without user state param)
  520. CodeMemberMethod am = new CodeMemberMethod ();
  521. am.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  522. am.Name = method.Name + "Async";
  523. am.ReturnType = new CodeTypeReference (typeof(void));
  524. CodeMethodInvokeExpression inv;
  525. inv = new CodeMethodInvokeExpression (ethis, am.Name);
  526. am.Statements.Add (inv);
  527. // On...Completed method
  528. CodeMemberMethod onCompleted = new CodeMemberMethod ();
  529. onCompleted.Name = "On" + messageName + "Completed";
  530. onCompleted.Attributes = MemberAttributes.Private | MemberAttributes.Final;
  531. onCompleted.ReturnType = new CodeTypeReference (typeof(void));
  532. onCompleted.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "arg"));
  533. CodeConditionStatement anIf = new CodeConditionStatement ();
  534. CodeExpression eventField = new CodeEventReferenceExpression (ethis, codeEvent.Name);
  535. anIf.Condition = new CodeBinaryOperatorExpression (eventField, CodeBinaryOperatorType.IdentityInequality, enull);
  536. CodeExpression castedArg = new CodeCastExpression (typeof(System.Web.Services.Protocols.InvokeCompletedEventArgs), new CodeVariableReferenceExpression ("arg"));
  537. CodeStatement invokeArgs = new CodeVariableDeclarationStatement (typeof(System.Web.Services.Protocols.InvokeCompletedEventArgs), "invokeArgs", castedArg);
  538. anIf.TrueStatements.Add (invokeArgs);
  539. CodeDelegateInvokeExpression delegateInvoke = new CodeDelegateInvokeExpression ();
  540. delegateInvoke.TargetObject = eventField;
  541. delegateInvoke.Parameters.Add (ethis);
  542. CodeObjectCreateExpression argsInstance = new CodeObjectCreateExpression (argsClassName);
  543. CodeExpression invokeArgsVar = new CodeVariableReferenceExpression ("invokeArgs");
  544. if (needsArgsClass) argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Results"));
  545. argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Error"));
  546. argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Cancelled"));
  547. argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "UserState"));
  548. delegateInvoke.Parameters.Add (argsInstance);
  549. anIf.TrueStatements.Add (delegateInvoke);
  550. onCompleted.Statements.Add (anIf);
  551. // Async method
  552. CodeMemberMethod asyncMethod = new CodeMemberMethod ();
  553. asyncMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  554. asyncMethod.Name = method.Name + "Async";
  555. asyncMethod.ReturnType = new CodeTypeReference (typeof(void));
  556. CodeExpression delegateField = new CodeFieldReferenceExpression (ethis, codeField.Name);
  557. anIf = new CodeConditionStatement ();
  558. anIf.Condition = new CodeBinaryOperatorExpression (delegateField, CodeBinaryOperatorType.IdentityEquality, enull);;
  559. CodeExpression delegateRef = new CodeMethodReferenceExpression (ethis, onCompleted.Name);
  560. CodeExpression newDelegate = new CodeObjectCreateExpression (typeof(System.Threading.SendOrPostCallback), delegateRef);
  561. CodeAssignStatement cas = new CodeAssignStatement (delegateField, newDelegate);
  562. anIf.TrueStatements.Add (cas);
  563. asyncMethod.Statements.Add (anIf);
  564. CodeArrayCreateExpression paramsArray = new CodeArrayCreateExpression (typeof(object));
  565. // Assign parameters
  566. CodeIdentifiers paramsIds = new CodeIdentifiers ();
  567. foreach (CodeParameterDeclarationExpression par in method.Parameters)
  568. {
  569. paramsIds.Add (par.Name, null);
  570. if (par.Direction == FieldDirection.In || par.Direction == FieldDirection.Ref) {
  571. CodeParameterDeclarationExpression inpar = new CodeParameterDeclarationExpression (par.Type, par.Name);
  572. am.Parameters.Add (inpar);
  573. asyncMethod.Parameters.Add (inpar);
  574. inv.Parameters.Add (new CodeVariableReferenceExpression (par.Name));
  575. paramsArray.Initializers.Add (new CodeVariableReferenceExpression (par.Name));
  576. }
  577. }
  578. inv.Parameters.Add (enull);
  579. string userStateName = paramsIds.AddUnique ("userState", null);
  580. asyncMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), userStateName));
  581. CodeExpression userStateVar = new CodeVariableReferenceExpression (userStateName);
  582. asyncMethod.Statements.Add (BuildInvokeAsync (messageName, paramsArray, delegateField, userStateVar));
  583. CodeTypeDeclaration.Members.Add (am);
  584. CodeTypeDeclaration.Members.Add (asyncMethod);
  585. CodeTypeDeclaration.Members.Add (onCompleted);
  586. asyncTypes.Add (delegateType);
  587. }
  588. CodeMemberProperty CreateArgsProperty (CodeTypeReference type, string name, int ind)
  589. {
  590. CodeMemberProperty prop = new CodeMemberProperty ();
  591. prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  592. prop.HasGet = true;
  593. prop.HasSet = false;
  594. prop.Name = name;
  595. prop.Type = type;
  596. CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
  597. CodeExpression thisResults = new CodeFieldReferenceExpression (ethis, "results");
  598. prop.GetStatements.Add (new CodeMethodInvokeExpression (ethis, "RaiseExceptionIfNecessary"));
  599. CodeArrayIndexerExpression arrValue = new CodeArrayIndexerExpression (thisResults, new CodePrimitiveExpression (ind));
  600. CodeExpression retval = new CodeCastExpression (type, arrValue);
  601. prop.GetStatements.Add (new CodeMethodReturnStatement (retval));
  602. return prop;
  603. }
  604. internal virtual CodeExpression BuildInvokeAsync (string messageName, CodeArrayCreateExpression paramsArray, CodeExpression delegateField, CodeExpression userStateVar)
  605. {
  606. CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
  607. CodeMethodInvokeExpression inv2 = new CodeMethodInvokeExpression (ethis, "InvokeAsync");
  608. inv2.Parameters.Add (new CodePrimitiveExpression (messageName));
  609. inv2.Parameters.Add (paramsArray);
  610. inv2.Parameters.Add (delegateField);
  611. inv2.Parameters.Add (userStateVar);
  612. return inv2;
  613. }
  614. #endif
  615. [MonoTODO]
  616. public void AddExtensionWarningComments (CodeCommentStatementCollection comments, ServiceDescriptionFormatExtensionCollection extensions)
  617. {
  618. throw new NotImplementedException ();
  619. }
  620. protected abstract CodeTypeDeclaration BeginClass ();
  621. protected virtual void BeginNamespace ()
  622. {
  623. }
  624. protected virtual void EndClass ()
  625. {
  626. }
  627. protected virtual void EndNamespace ()
  628. {
  629. }
  630. protected abstract CodeMemberMethod GenerateMethod ();
  631. protected abstract bool IsBindingSupported ();
  632. protected abstract bool IsOperationFlowSupported (OperationFlow flow);
  633. [MonoTODO]
  634. public Exception OperationBindingSyntaxException (string text)
  635. {
  636. throw new NotImplementedException ();
  637. }
  638. [MonoTODO]
  639. public Exception OperationSyntaxException (string text)
  640. {
  641. throw new NotImplementedException ();
  642. }
  643. public void UnsupportedBindingWarning (string text)
  644. {
  645. warnings |= ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored;
  646. AddGlobalComments ("WARNING: Could not generate proxy for binding " + binding.Name + ". " + text);
  647. }
  648. public void UnsupportedOperationBindingWarning (string text)
  649. {
  650. warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
  651. AddGlobalComments ("WARNING: Could not generate operation binding " + OperationBinding.Name + ". " + text);
  652. }
  653. public void UnsupportedOperationWarning (string text)
  654. {
  655. warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
  656. AddGlobalComments ("WARNING: Could not generate operation " + Operation.Name + ". " + text);
  657. }
  658. void AddGlobalComments (string comments)
  659. {
  660. codeNamespace.Comments.Add (new CodeCommentStatement (comments, false));
  661. }
  662. void AddComments (CodeTypeMember member, string comments)
  663. {
  664. if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  665. else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
  666. }
  667. void AddCodeType (CodeTypeDeclaration type, string comments)
  668. {
  669. AddComments (type, comments);
  670. codeNamespace.Types.Add (type);
  671. }
  672. internal void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
  673. {
  674. if (att.Arguments.Count == 0 && !addIfNoParams) return;
  675. if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
  676. ctm.CustomAttributes.Add (att);
  677. }
  678. internal void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
  679. {
  680. if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
  681. ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
  682. }
  683. internal CodeAttributeArgument GetArg (string name, object value)
  684. {
  685. return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
  686. }
  687. internal CodeAttributeArgument GetEnumArg (string name, string enumType, string enumValue)
  688. {
  689. return new CodeAttributeArgument (name, new CodeFieldReferenceExpression (new CodeTypeReferenceExpression(enumType), enumValue));
  690. }
  691. internal CodeAttributeArgument GetArg (object value)
  692. {
  693. return new CodeAttributeArgument (new CodePrimitiveExpression(value));
  694. }
  695. internal CodeAttributeArgument GetTypeArg (string name, string typeName)
  696. {
  697. return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
  698. }
  699. #endregion
  700. }
  701. }