ProtocolImporter.cs 28 KB

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