ServiceContractGenerator.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. //
  2. // ServiceContractGenerator.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2005 Novell, Inc. http://www.novell.com
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.CodeDom;
  30. using System.Collections.Generic;
  31. using System.Collections.ObjectModel;
  32. using System.Configuration;
  33. using System.Reflection;
  34. using System.Runtime.Serialization;
  35. using System.ServiceModel;
  36. using System.ServiceModel.Channels;
  37. using System.ServiceModel.Configuration;
  38. using System.Xml.Schema;
  39. using System.Xml.Serialization;
  40. using ConfigurationType = System.Configuration.Configuration;
  41. using QName = System.Xml.XmlQualifiedName;
  42. namespace System.ServiceModel.Description
  43. {
  44. public class ServiceContractGenerator
  45. {
  46. CodeCompileUnit ccu;
  47. ConfigurationType config;
  48. Collection<MetadataConversionError> errors
  49. = new Collection<MetadataConversionError> ();
  50. Dictionary<string,string> nsmappings
  51. = new Dictionary<string,string> ();
  52. Dictionary<ContractDescription,Type> referenced_types
  53. = new Dictionary<ContractDescription,Type> ();
  54. ServiceContractGenerationOptions options;
  55. Dictionary<QName, QName> imported_names = null;
  56. public ServiceContractGenerator ()
  57. : this (null, null)
  58. {
  59. }
  60. public ServiceContractGenerator (CodeCompileUnit ccu)
  61. : this (ccu, null)
  62. {
  63. }
  64. public ServiceContractGenerator (ConfigurationType config)
  65. : this (null, config)
  66. {
  67. }
  68. public ServiceContractGenerator (CodeCompileUnit ccu, ConfigurationType config)
  69. {
  70. if (ccu == null)
  71. this.ccu = new CodeCompileUnit ();
  72. else
  73. this.ccu = ccu;
  74. this.config = config;
  75. Options |= ServiceContractGenerationOptions.ChannelInterface |
  76. ServiceContractGenerationOptions.ClientClass;
  77. }
  78. public ConfigurationType Configuration {
  79. get { return config; }
  80. }
  81. public Collection<MetadataConversionError> Errors {
  82. get { return errors; }
  83. }
  84. public Dictionary<string,string> NamespaceMappings {
  85. get { return nsmappings; }
  86. }
  87. public ServiceContractGenerationOptions Options {
  88. get { return options; }
  89. set { options = value; }
  90. }
  91. bool GenerateAsync {
  92. get { return (options & ServiceContractGenerationOptions.AsynchronousMethods) != 0; }
  93. }
  94. public Dictionary<ContractDescription,Type> ReferencedTypes {
  95. get { return referenced_types; }
  96. }
  97. public CodeCompileUnit TargetCompileUnit {
  98. get { return ccu; }
  99. }
  100. [MonoTODO]
  101. public void GenerateBinding (Binding binding,
  102. out string bindingSectionName,
  103. out string configurationName)
  104. {
  105. throw new NotImplementedException ();
  106. }
  107. #region Service Contract Type
  108. // Those implementation classes are very likely to be split
  109. // into different classes.
  110. [MonoTODO]
  111. public CodeTypeReference GenerateServiceContractType (
  112. ContractDescription contractDescription)
  113. {
  114. CodeNamespace cns = GetNamespace (contractDescription.Namespace);
  115. imported_names = new Dictionary<QName, QName> ();
  116. try {
  117. return ExportInterface (contractDescription, cns);
  118. } finally {
  119. if ((Options & ServiceContractGenerationOptions.ClientClass) != 0)
  120. GenerateProxyClass (contractDescription, cns);
  121. if ((Options & ServiceContractGenerationOptions.ChannelInterface) != 0)
  122. GenerateChannelInterface (contractDescription, cns);
  123. }
  124. }
  125. CodeNamespace GetNamespace (string ns)
  126. {
  127. if (ns == null)
  128. ns = String.Empty;
  129. foreach (CodeNamespace cns in ccu.Namespaces)
  130. if (cns.Name == ns)
  131. return cns;
  132. CodeNamespace ncns = new CodeNamespace ();
  133. //ncns.Name = ns;
  134. ccu.Namespaces.Add (ncns);
  135. return ncns;
  136. }
  137. CodeTypeDeclaration GetTypeDeclaration (CodeNamespace cns, string name)
  138. {
  139. foreach (CodeTypeDeclaration type in cns.Types)
  140. if (type.Name == name)
  141. return type;
  142. return null;
  143. }
  144. void GenerateProxyClass (ContractDescription cd, CodeNamespace cns)
  145. {
  146. string name = cd.Name + "Client";
  147. if (name [0] == 'I')
  148. name = name.Substring (1);
  149. CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
  150. if (type != null)
  151. return; // already imported
  152. CodeTypeReference clientBase = new CodeTypeReference (typeof (ClientBase<>));
  153. clientBase.TypeArguments.Add (new CodeTypeReference (cd.Name));
  154. type = new CodeTypeDeclaration (name);
  155. cns.Types.Add (type);
  156. type.TypeAttributes = TypeAttributes.Public;
  157. type.BaseTypes.Add (clientBase);
  158. type.BaseTypes.Add (new CodeTypeReference (cd.Name));
  159. // .ctor()
  160. CodeConstructor ctor = new CodeConstructor ();
  161. ctor.Attributes = MemberAttributes.Public;
  162. type.Members.Add (ctor);
  163. // .ctor(string endpointConfigurationName)
  164. ctor = new CodeConstructor ();
  165. ctor.Attributes = MemberAttributes.Public;
  166. ctor.Parameters.Add (
  167. new CodeParameterDeclarationExpression (
  168. new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
  169. ctor.BaseConstructorArgs.Add (
  170. new CodeArgumentReferenceExpression ("endpointConfigurationName"));
  171. type.Members.Add (ctor);
  172. // .ctor(string endpointConfigurationName, string remoteAddress)
  173. ctor = new CodeConstructor ();
  174. ctor.Attributes = MemberAttributes.Public;
  175. ctor.Parameters.Add (
  176. new CodeParameterDeclarationExpression (
  177. new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
  178. ctor.Parameters.Add (
  179. new CodeParameterDeclarationExpression (
  180. new CodeTypeReference (typeof (string)), "remoteAddress"));
  181. ctor.BaseConstructorArgs.Add (
  182. new CodeArgumentReferenceExpression ("endpointConfigurationName"));
  183. ctor.BaseConstructorArgs.Add (
  184. new CodeArgumentReferenceExpression ("remoteAddress"));
  185. type.Members.Add (ctor);
  186. // .ctor(string endpointConfigurationName, EndpointAddress remoteAddress)
  187. ctor = new CodeConstructor ();
  188. ctor.Attributes = MemberAttributes.Public;
  189. ctor.Parameters.Add (
  190. new CodeParameterDeclarationExpression (
  191. new CodeTypeReference (typeof (string)), "endpointConfigurationName"));
  192. ctor.Parameters.Add (
  193. new CodeParameterDeclarationExpression (
  194. new CodeTypeReference (typeof (EndpointAddress)), "remoteAddress"));
  195. ctor.BaseConstructorArgs.Add (
  196. new CodeArgumentReferenceExpression ("endpointConfigurationName"));
  197. ctor.BaseConstructorArgs.Add (
  198. new CodeArgumentReferenceExpression ("remoteAddress"));
  199. type.Members.Add (ctor);
  200. // .ctor(Binding,EndpointAddress)
  201. ctor = new CodeConstructor ();
  202. ctor.Attributes = MemberAttributes.Public;
  203. ctor.Parameters.Add (
  204. new CodeParameterDeclarationExpression (
  205. new CodeTypeReference (typeof (Binding)), "binding"));
  206. ctor.Parameters.Add (
  207. new CodeParameterDeclarationExpression (
  208. new CodeTypeReference (typeof (EndpointAddress)), "endpoint"));
  209. ctor.BaseConstructorArgs.Add (
  210. new CodeArgumentReferenceExpression ("binding"));
  211. ctor.BaseConstructorArgs.Add (
  212. new CodeArgumentReferenceExpression ("endpoint"));
  213. type.Members.Add (ctor);
  214. // service contract methods
  215. AddImplementationMethods (type, cd);
  216. }
  217. void GenerateChannelInterface (ContractDescription cd, CodeNamespace cns)
  218. {
  219. string name = cd.Name + "Channel";
  220. CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
  221. if (type != null)
  222. return;
  223. type = new CodeTypeDeclaration ();
  224. type.Name = name;
  225. type.TypeAttributes = TypeAttributes.Interface | TypeAttributes.Public;
  226. cns.Types.Add (type);
  227. type.BaseTypes.Add (ExportInterface (cd, cns));
  228. type.BaseTypes.Add (new CodeTypeReference (typeof (System.ServiceModel.IClientChannel)));
  229. }
  230. CodeTypeReference ExportInterface (ContractDescription cd, CodeNamespace cns)
  231. {
  232. CodeTypeDeclaration type = GetTypeDeclaration (cns, cd.Name);
  233. if (type != null)
  234. return new CodeTypeReference (type.Name);
  235. type = new CodeTypeDeclaration ();
  236. type.TypeAttributes = TypeAttributes.Interface;
  237. type.TypeAttributes |= TypeAttributes.Public;
  238. cns.Types.Add (type);
  239. type.Name = cd.Name;
  240. CodeAttributeDeclaration ad =
  241. new CodeAttributeDeclaration (
  242. new CodeTypeReference (
  243. typeof (ServiceContractAttribute)));
  244. ad.Arguments.Add (new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (cd.Namespace)));
  245. type.CustomAttributes.Add (ad);
  246. AddOperationMethods (type, cd);
  247. return new CodeTypeReference (type.Name);
  248. }
  249. void AddBeginAsyncArgs (CodeMemberMethod cm)
  250. {
  251. var acb = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback");
  252. cm.Parameters.Add (acb);
  253. var us = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState");
  254. cm.Parameters.Add (us);
  255. }
  256. void AddOperationMethods (CodeTypeDeclaration type, ContractDescription cd)
  257. {
  258. foreach (OperationDescription od in cd.Operations) {
  259. CodeMemberMethod cm = new CodeMemberMethod ();
  260. type.Members.Add (cm);
  261. if (GenerateAsync)
  262. cm.Name = "Begin" + od.Name;
  263. else
  264. cm.Name = od.Name;
  265. CodeTypeReference returnTypeFromMessageContract = null;
  266. if (od.SyncMethod != null) {
  267. ExportParameters (cm, od.SyncMethod.GetParameters ());
  268. if (GenerateAsync) {
  269. AddBeginAsyncArgs (cm);
  270. cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
  271. }
  272. else
  273. cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
  274. } else {
  275. ExportMessages (od.Messages, cm, false);
  276. returnTypeFromMessageContract = cm.ReturnType;
  277. if (GenerateAsync) {
  278. AddBeginAsyncArgs (cm);
  279. cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
  280. }
  281. }
  282. // [OperationContract (Action = "...", ReplyAction = "..")]
  283. CodeAttributeDeclaration ad =
  284. new CodeAttributeDeclaration (
  285. new CodeTypeReference (
  286. typeof (OperationContractAttribute)));
  287. foreach (MessageDescription md in od.Messages) {
  288. if (md.Direction == MessageDirection.Input)
  289. ad.Arguments.Add (new CodeAttributeArgument ("Action", new CodePrimitiveExpression (md.Action)));
  290. else
  291. ad.Arguments.Add (new CodeAttributeArgument ("ReplyAction", new CodePrimitiveExpression (md.Action)));
  292. }
  293. if (GenerateAsync)
  294. ad.Arguments.Add (new CodeAttributeArgument ("AsyncPattern", new CodePrimitiveExpression (true)));
  295. cm.CustomAttributes.Add (ad);
  296. // For async mode, add EndXxx() too.
  297. if (!GenerateAsync)
  298. return;
  299. cm = new CodeMemberMethod ();
  300. type.Members.Add (cm);
  301. cm.Name = "End" + od.Name;
  302. var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
  303. cm.Parameters.Add (res);
  304. if (od.SyncMethod != null) // FIXME: it depends on sync method!
  305. cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
  306. else
  307. cm.ReturnType = returnTypeFromMessageContract;
  308. }
  309. }
  310. void ExportParameters (CodeMemberMethod method, ParameterInfo [] parameters)
  311. {
  312. foreach (ParameterInfo pi in parameters)
  313. method.Parameters.Add (
  314. new CodeParameterDeclarationExpression (
  315. new CodeTypeReference (pi.ParameterType),
  316. pi.Name));
  317. }
  318. void AddImplementationMethods (CodeTypeDeclaration type, ContractDescription cd)
  319. {
  320. foreach (OperationDescription od in cd.Operations) {
  321. CodeMemberMethod cm = new CodeMemberMethod ();
  322. type.Members.Add (cm);
  323. if (GenerateAsync)
  324. cm.Name = "Begin" + od.Name;
  325. else
  326. cm.Name = od.Name;
  327. cm.Attributes = MemberAttributes.Public
  328. | MemberAttributes.Final;
  329. CodeTypeReference returnTypeFromMessageContract = null;
  330. List<CodeExpression> args = new List<CodeExpression> ();
  331. if (od.SyncMethod != null) {
  332. ParameterInfo [] pars = od.SyncMethod.GetParameters ();
  333. ExportParameters (cm, pars);
  334. cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
  335. int i = 0;
  336. foreach (ParameterInfo pi in pars)
  337. args.Add (new CodeArgumentReferenceExpression (pi.Name));
  338. } else {
  339. args.AddRange (ExportMessages (od.Messages, cm, true));
  340. returnTypeFromMessageContract = cm.ReturnType;
  341. if (GenerateAsync) {
  342. AddBeginAsyncArgs (cm);
  343. cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
  344. }
  345. }
  346. if (GenerateAsync) {
  347. args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
  348. args.Add (new CodeArgumentReferenceExpression ("userState"));
  349. }
  350. CodeExpression call = new CodeMethodInvokeExpression (
  351. new CodePropertyReferenceExpression (
  352. new CodeBaseReferenceExpression (),
  353. "Channel"),
  354. cm.Name,
  355. args.ToArray ());
  356. if (cm.ReturnType.BaseType == "System.Void")
  357. cm.Statements.Add (new CodeExpressionStatement (call));
  358. else
  359. cm.Statements.Add (new CodeMethodReturnStatement (call));
  360. // For async mode, add EndXxx() too.
  361. if (!GenerateAsync)
  362. return;
  363. // EndXxx() implementation
  364. cm = new CodeMemberMethod ();
  365. type.Members.Add (cm);
  366. cm.Name = "End" + od.Name;
  367. var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
  368. cm.Parameters.Add (res);
  369. if (od.SyncMethod != null) // FIXME: it depends on sync method!
  370. cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
  371. else
  372. cm.ReturnType = returnTypeFromMessageContract;
  373. string resultArgName = "result";
  374. if (od.EndMethod != null)
  375. resultArgName = od.EndMethod.GetParameters () [0].Name;
  376. call = new CodeMethodInvokeExpression (
  377. new CodePropertyReferenceExpression (
  378. new CodeBaseReferenceExpression (),
  379. "Channel"),
  380. cm.Name,
  381. new CodeArgumentReferenceExpression (resultArgName));
  382. if (cm.ReturnType.BaseType == "System.Void")
  383. cm.Statements.Add (new CodeExpressionStatement (call));
  384. else
  385. cm.Statements.Add (new CodeMethodReturnStatement (call));
  386. }
  387. }
  388. private CodeExpression[] ExportMessages (MessageDescriptionCollection messages, CodeMemberMethod method, bool return_args)
  389. {
  390. CodeExpression [] args = null;
  391. foreach (MessageDescription md in messages) {
  392. if (md.Direction == MessageDirection.Output) {
  393. if (md.Body.ReturnValue != null) {
  394. ExportDataContract (md.Body.ReturnValue.XmlTypeMapping);
  395. method.ReturnType = new CodeTypeReference (md.Body.ReturnValue.TypeName.Name);
  396. }
  397. continue;
  398. }
  399. if (return_args)
  400. args = new CodeExpression [md.Body.Parts.Count];
  401. MessagePartDescriptionCollection parts = md.Body.Parts;
  402. for (int i = 0; i < parts.Count; i++) {
  403. ExportDataContract (parts [i].XmlTypeMapping);
  404. method.Parameters.Add (
  405. new CodeParameterDeclarationExpression (
  406. new CodeTypeReference (parts [i].TypeName.Name),
  407. parts [i].Name));
  408. if (return_args)
  409. args [i] = new CodeArgumentReferenceExpression (parts [i].Name);
  410. }
  411. }
  412. return args;
  413. }
  414. #endregion
  415. [MonoTODO]
  416. public CodeTypeReference GenerateServiceEndpoint (
  417. ServiceEndpoint endpoint,
  418. out ChannelEndpointElement channelElement)
  419. {
  420. throw new NotImplementedException ();
  421. }
  422. private void ExportDataContract (XmlTypeMapping mapping)
  423. {
  424. if (mapping == null)
  425. return;
  426. QName qname = new QName (mapping.TypeName, mapping.Namespace);
  427. if (imported_names.ContainsKey (qname))
  428. return;
  429. CodeNamespace cns = new CodeNamespace ();
  430. XmlCodeExporter xce = new XmlCodeExporter (cns);
  431. xce.ExportTypeMapping (mapping);
  432. List <CodeTypeDeclaration> to_remove = new List <CodeTypeDeclaration> ();
  433. //Process the types just generated
  434. //FIXME: Iterate and assign the types to correct namespaces
  435. //At the end, add all those namespaces to the ccu
  436. foreach (CodeTypeDeclaration type in cns.Types) {
  437. string ns = GetXmlNamespace (type);
  438. if (ns == null)
  439. //FIXME: do what here?
  440. continue;
  441. QName type_name = new QName (type.Name, ns);
  442. if (imported_names.ContainsKey (type_name)) {
  443. //Type got reemitted, so remove it!
  444. to_remove.Add (type);
  445. continue;
  446. }
  447. imported_names [type_name] = type_name;
  448. type.Comments.Clear ();
  449. //Custom Attributes
  450. type.CustomAttributes.Clear ();
  451. if (type.IsEnum)
  452. continue;
  453. type.CustomAttributes.Add (
  454. new CodeAttributeDeclaration (
  455. new CodeTypeReference ("System.CodeDom.Compiler.GeneratedCodeAttribute"),
  456. new CodeAttributeArgument (new CodePrimitiveExpression ("System.Runtime.Serialization")),
  457. new CodeAttributeArgument (new CodePrimitiveExpression ("3.0.0.0"))));
  458. type.CustomAttributes.Add (
  459. new CodeAttributeDeclaration (
  460. new CodeTypeReference ("System.Runtime.Serialization.DataContractAttribute")));
  461. //BaseType and interface
  462. type.BaseTypes.Add (new CodeTypeReference (typeof (object)));
  463. type.BaseTypes.Add (new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject"));
  464. foreach (CodeTypeMember mbr in type.Members) {
  465. CodeMemberProperty p = mbr as CodeMemberProperty;
  466. if (p == null)
  467. continue;
  468. if ((p.Attributes & MemberAttributes.Public) == MemberAttributes.Public) {
  469. //FIXME: Clear all attributes or only XmlElementAttribute?
  470. p.CustomAttributes.Clear ();
  471. p.CustomAttributes.Add (new CodeAttributeDeclaration (
  472. new CodeTypeReference ("System.Runtime.Serialization.DataMemberAttribute")));
  473. p.Comments.Clear ();
  474. }
  475. }
  476. //Fields
  477. CodeMemberField field = new CodeMemberField (
  478. new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject"),
  479. "extensionDataField");
  480. field.Attributes = MemberAttributes.Private | MemberAttributes.Final;
  481. type.Members.Add (field);
  482. //Property
  483. CodeMemberProperty prop = new CodeMemberProperty ();
  484. prop.Type = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
  485. prop.Name = "ExtensionData";
  486. prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  487. //Get
  488. prop.GetStatements.Add (new CodeMethodReturnStatement (
  489. new CodeFieldReferenceExpression (
  490. new CodeThisReferenceExpression (),
  491. "extensionDataField")));
  492. //Set
  493. prop.SetStatements.Add (new CodeAssignStatement (
  494. new CodeFieldReferenceExpression (
  495. new CodeThisReferenceExpression (),
  496. "extensionDataField"),
  497. new CodePropertySetValueReferenceExpression ()));
  498. type.Members.Add (prop);
  499. }
  500. foreach (CodeTypeDeclaration type in to_remove)
  501. cns.Types.Remove (type);
  502. ccu.Namespaces.Add (cns);
  503. }
  504. private string GetXmlNamespace (CodeTypeDeclaration type)
  505. {
  506. foreach (CodeAttributeDeclaration attr in type.CustomAttributes) {
  507. if (attr.Name == "System.Xml.Serialization.XmlTypeAttribute" ||
  508. attr.Name == "System.Xml.Serialization.XmlRootAttribute") {
  509. foreach (CodeAttributeArgument arg in attr.Arguments)
  510. if (arg.Name == "Namespace")
  511. return ((CodePrimitiveExpression)arg.Value).Value as string;
  512. //Could not find Namespace arg!
  513. return null;
  514. }
  515. }
  516. return null;
  517. }
  518. }
  519. }