WebServicesConfigurationSectionHandler.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. //
  2. // System.Web.Services.Configuration.WebServicesConfigurationSectionHandler
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2003 Ximian, Inc (http://www.ximian.com)
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections;
  31. using System.Configuration;
  32. using System.Xml;
  33. namespace System.Web.Services.Configuration
  34. {
  35. [Flags]
  36. enum WSProtocol
  37. {
  38. HttpSoap = 1,
  39. HttpPost = 1 << 1,
  40. HttpGet = 1 << 2,
  41. Documentation = 1 << 3,
  42. #if NET_1_1
  43. HttpSoap12 = 1 << 4,
  44. HttpPostLocalhost = 1 << 5,
  45. #endif
  46. All = 0xFF
  47. }
  48. class WSConfig
  49. {
  50. #if !TARGET_JVM
  51. volatile static WSConfig instance;
  52. #else
  53. static WSConfig instance {
  54. get {
  55. return (WSConfig)AppDomain.CurrentDomain.GetData("WSConfig.instance");
  56. }
  57. set {
  58. AppDomain.CurrentDomain.SetData("WSConfig.instance", value);
  59. }
  60. }
  61. #endif
  62. WSProtocol protocols;
  63. string wsdlHelpPage;
  64. string filePath;
  65. ArrayList extensionTypes = new ArrayList();
  66. ArrayList extensionImporterTypes = new ArrayList();
  67. ArrayList extensionReflectorTypes = new ArrayList();
  68. ArrayList formatExtensionTypes = new ArrayList();
  69. static readonly object lockobj = new object ();
  70. public WSConfig (WSConfig parent, object context)
  71. {
  72. if (parent == null)
  73. return;
  74. protocols = parent.protocols;
  75. wsdlHelpPage = parent.wsdlHelpPage;
  76. if (wsdlHelpPage != null)
  77. filePath = parent.filePath;
  78. else
  79. filePath = context as string;
  80. }
  81. static WSProtocol ParseProtocol (string protoName, out string error)
  82. {
  83. WSProtocol proto;
  84. error = null;
  85. #if ONLY_1_1
  86. switch (protoName) {
  87. case "HttpSoap1.2":
  88. protoName = "HttpSoap12";
  89. break;
  90. case "HttpSoap12":
  91. protoName = null;
  92. break;
  93. }
  94. #endif
  95. try {
  96. proto = (WSProtocol) Enum.Parse (typeof (WSProtocol), protoName);
  97. } catch {
  98. error = "Invalid protocol name";
  99. return 0;
  100. }
  101. return proto;
  102. }
  103. // Methods to modify configuration values
  104. public bool AddProtocol (string protoName, out string error)
  105. {
  106. if (protoName == "All") {
  107. error = "Invalid protocol name";
  108. return false;
  109. }
  110. WSProtocol proto = ParseProtocol (protoName, out error);
  111. if (error != null)
  112. return false;
  113. protocols |= proto;
  114. return true;
  115. }
  116. public bool RemoveProtocol (string protoName, out string error)
  117. {
  118. if (protoName == "All") {
  119. error = "Invalid protocol name";
  120. return false;
  121. }
  122. WSProtocol proto = ParseProtocol (protoName, out error);
  123. if (error != null)
  124. return false;
  125. protocols &= ~proto;
  126. return true;
  127. }
  128. public void ClearProtocol ()
  129. {
  130. protocols = 0;
  131. }
  132. // Methods to query/get configuration
  133. public static bool IsSupported (WSProtocol proto)
  134. {
  135. return ((Instance.protocols & proto) == proto && (proto != 0) && (proto != WSProtocol.All));
  136. }
  137. // Properties
  138. public string WsdlHelpPage {
  139. get { return wsdlHelpPage; }
  140. set { wsdlHelpPage = value; }
  141. }
  142. public string ConfigFilePath {
  143. get { return filePath; }
  144. set { filePath = value; }
  145. }
  146. static public WSConfig Instance {
  147. get {
  148. //TODO: use HttpContext to get the configuration
  149. if (instance != null)
  150. return instance;
  151. lock (lockobj) {
  152. if (instance != null)
  153. return instance;
  154. instance = (WSConfig) ConfigurationSettings.GetConfig ("system.web/webServices");
  155. }
  156. return instance;
  157. }
  158. }
  159. public ArrayList ExtensionTypes {
  160. get { return extensionTypes; }
  161. }
  162. public ArrayList ExtensionImporterTypes {
  163. get { return extensionImporterTypes; }
  164. }
  165. public ArrayList ExtensionReflectorTypes {
  166. get { return extensionReflectorTypes; }
  167. }
  168. public ArrayList FormatExtensionTypes {
  169. get { return formatExtensionTypes; }
  170. }
  171. }
  172. enum WSExtensionGroup
  173. {
  174. High,
  175. Low
  176. }
  177. class WSExtensionConfig
  178. {
  179. Type type;
  180. int priority;
  181. WSExtensionGroup group;
  182. public Exception SetType (string typeName)
  183. {
  184. Exception exc = null;
  185. try {
  186. type = Type.GetType (typeName, true);
  187. } catch (Exception e) {
  188. exc = e;
  189. }
  190. return exc;
  191. }
  192. public Exception SetPriority (string prio)
  193. {
  194. if (prio == null || prio == "")
  195. return null;
  196. Exception exc = null;
  197. try {
  198. priority = Int32.Parse (prio);
  199. } catch (Exception e) {
  200. exc = e;
  201. }
  202. return exc;
  203. }
  204. public Exception SetGroup (string grp)
  205. {
  206. if (grp == null || grp == "")
  207. return null;
  208. Exception exc = null;
  209. try {
  210. group = (WSExtensionGroup) Int32.Parse (grp);
  211. if (group < WSExtensionGroup.High || group > WSExtensionGroup.Low)
  212. throw new ArgumentOutOfRangeException ("group", "Must be 0 or 1");
  213. } catch (Exception e) {
  214. exc = e;
  215. }
  216. return exc;
  217. }
  218. // Getters
  219. public Type Type {
  220. get { return type; }
  221. }
  222. public int Priority {
  223. get { return priority; }
  224. }
  225. public WSExtensionGroup Group {
  226. get { return group; }
  227. }
  228. }
  229. class WebServicesConfigurationSectionHandler : IConfigurationSectionHandler
  230. {
  231. public object Create (object parent, object context, XmlNode section)
  232. {
  233. WSConfig config = new WSConfig (parent as WSConfig, context);
  234. if (section.Attributes != null && section.Attributes.Count != 0)
  235. ThrowException ("Unrecognized attribute", section);
  236. XmlNodeList nodes = section.ChildNodes;
  237. foreach (XmlNode child in nodes) {
  238. XmlNodeType ntype = child.NodeType;
  239. if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
  240. continue;
  241. if (ntype != XmlNodeType.Element)
  242. ThrowException ("Only elements allowed", child);
  243. string name = child.Name;
  244. if (name == "protocols") {
  245. ConfigProtocols (child, config);
  246. continue;
  247. }
  248. if (name == "soapExtensionTypes") {
  249. ConfigSoapExtensionTypes (child, config.ExtensionTypes);
  250. continue;
  251. }
  252. if (name == "soapExtensionReflectorTypes") {
  253. ConfigSoapExtensionTypes (child, config.ExtensionReflectorTypes);
  254. continue;
  255. }
  256. if (name == "soapExtensionImporterTypes") {
  257. ConfigSoapExtensionTypes (child, config.ExtensionImporterTypes);
  258. continue;
  259. }
  260. if (name == "serviceDescriptionFormatExtensionTypes") {
  261. ConfigFormatExtensionTypes (child, config);
  262. continue;
  263. }
  264. if (name == "wsdlHelpGenerator") {
  265. string href = AttValue ("href", child, false);
  266. if (child.Attributes != null && child.Attributes.Count != 0)
  267. HandlersUtil.ThrowException ("Unrecognized attribute", child);
  268. config.ConfigFilePath = context as string;
  269. config.WsdlHelpPage = href;
  270. continue;
  271. }
  272. ThrowException ("Unexpected element", child);
  273. }
  274. return config;
  275. }
  276. static void ConfigProtocols (XmlNode section, WSConfig config)
  277. {
  278. if (section.Attributes != null && section.Attributes.Count != 0)
  279. ThrowException ("Unrecognized attribute", section);
  280. XmlNodeList nodes = section.ChildNodes;
  281. foreach (XmlNode child in nodes) {
  282. XmlNodeType ntype = child.NodeType;
  283. if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
  284. continue;
  285. if (ntype != XmlNodeType.Element)
  286. ThrowException ("Only elements allowed", child);
  287. string name = child.Name;
  288. string error;
  289. if (name == "add") {
  290. string protoName = AttValue ("name", child, false);
  291. if (child.Attributes != null && child.Attributes.Count != 0)
  292. HandlersUtil.ThrowException ("Unrecognized attribute", child);
  293. if (!config.AddProtocol (protoName, out error))
  294. ThrowException (error, child);
  295. continue;
  296. }
  297. if (name == "remove") {
  298. string protoName = AttValue ("name", child, false);
  299. if (child.Attributes != null && child.Attributes.Count != 0)
  300. HandlersUtil.ThrowException ("Unrecognized attribute", child);
  301. if (!config.RemoveProtocol (protoName, out error))
  302. ThrowException (error, child);
  303. continue;
  304. }
  305. if (name == "clear") {
  306. if (child.Attributes != null && child.Attributes.Count != 0)
  307. HandlersUtil.ThrowException ("Unrecognized attribute", child);
  308. config.ClearProtocol ();
  309. continue;
  310. }
  311. ThrowException ("Unexpected element", child);
  312. }
  313. }
  314. static void ConfigSoapExtensionTypes (XmlNode section, ArrayList extensions)
  315. {
  316. if (section.Attributes != null && section.Attributes.Count != 0)
  317. ThrowException ("Unrecognized attribute", section);
  318. XmlNodeList nodes = section.ChildNodes;
  319. foreach (XmlNode child in nodes) {
  320. XmlNodeType ntype = child.NodeType;
  321. if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
  322. continue;
  323. if (ntype != XmlNodeType.Element)
  324. ThrowException ("Only elements allowed", child);
  325. string name = child.Name;
  326. if (name == "add") {
  327. string seType = AttValue ("type", child, false);
  328. string priority = AttValue ("priority", child);
  329. string group = AttValue ("group", child);
  330. if (child.Attributes != null && child.Attributes.Count != 0)
  331. HandlersUtil.ThrowException ("Unrecognized attribute", child);
  332. WSExtensionConfig wse = new WSExtensionConfig ();
  333. Exception e = wse.SetType (seType);
  334. if (e != null)
  335. ThrowException (e.Message, child);
  336. e = wse.SetPriority (priority);
  337. if (e != null)
  338. ThrowException (e.Message, child);
  339. e = wse.SetGroup (group);
  340. if (e != null)
  341. ThrowException (e.Message, child);
  342. extensions.Add (wse);
  343. continue;
  344. }
  345. ThrowException ("Unexpected element", child);
  346. }
  347. }
  348. static void ConfigFormatExtensionTypes (XmlNode section, WSConfig config)
  349. {
  350. if (section.Attributes != null && section.Attributes.Count != 0)
  351. ThrowException ("Unrecognized attribute", section);
  352. XmlNodeList nodes = section.ChildNodes;
  353. foreach (XmlNode child in nodes) {
  354. XmlNodeType ntype = child.NodeType;
  355. if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
  356. continue;
  357. if (ntype != XmlNodeType.Element)
  358. ThrowException ("Only elements allowed", child);
  359. string name = child.Name;
  360. if (name == "add") {
  361. string typeName = AttValue ("name", child, false);
  362. if (child.Attributes != null && child.Attributes.Count != 0)
  363. HandlersUtil.ThrowException ("Unrecognized attribute", child);
  364. try {
  365. config.FormatExtensionTypes.Add (Type.GetType (typeName, true));
  366. } catch (Exception e) {
  367. ThrowException (e.Message, child);
  368. }
  369. continue;
  370. }
  371. ThrowException ("Unexpected element", child);
  372. }
  373. }
  374. // To save some typing...
  375. static string AttValue (string name, XmlNode node, bool optional)
  376. {
  377. return HandlersUtil.ExtractAttributeValue (name, node, optional);
  378. }
  379. static string AttValue (string name, XmlNode node)
  380. {
  381. return HandlersUtil.ExtractAttributeValue (name, node, true);
  382. }
  383. static void ThrowException (string message, XmlNode node)
  384. {
  385. HandlersUtil.ThrowException (message, node);
  386. }
  387. //
  388. }
  389. class HandlersUtil
  390. {
  391. private HandlersUtil ()
  392. {
  393. }
  394. static internal string ExtractAttributeValue (string attKey, XmlNode node)
  395. {
  396. return ExtractAttributeValue (attKey, node, false);
  397. }
  398. static internal string ExtractAttributeValue (string attKey, XmlNode node, bool optional)
  399. {
  400. if (node.Attributes == null) {
  401. if (optional)
  402. return null;
  403. ThrowException ("Required attribute not found: " + attKey, node);
  404. }
  405. XmlNode att = node.Attributes.RemoveNamedItem (attKey);
  406. if (att == null) {
  407. if (optional)
  408. return null;
  409. ThrowException ("Required attribute not found: " + attKey, node);
  410. }
  411. string value = att.Value;
  412. if (value == String.Empty) {
  413. string opt = optional ? "Optional" : "Required";
  414. ThrowException (opt + " attribute is empty: " + attKey, node);
  415. }
  416. return value;
  417. }
  418. static internal void ThrowException (string msg, XmlNode node)
  419. {
  420. if (node != null && node.Name != String.Empty)
  421. msg = msg + " (node name: " + node.Name + ") ";
  422. throw new ConfigurationException (msg, node);
  423. }
  424. }
  425. }