// // System.Web.Services.Configuration.WebServicesConfigurationSectionHandler // // Authors: // Gonzalo Paniagua Javier (gonzalo@ximian.com) // // (C) 2003 Ximian, Inc (http://www.ximian.com) // using System; using System.Collections; using System.Configuration; using System.Xml; namespace System.Web.Services.Configuration { [Flags] enum WSProtocol { HttpSoap = 1, HttpPost = 1 << 1, HttpGet = 1 << 2, Documentation = 1 << 3, All = 0x0F } class WSConfig { static WSConfig instance; WSProtocol protocols; string wsdlHelpPage; string filePath; ArrayList extensionTypes = new ArrayList(); ArrayList extensionImporterTypes = new ArrayList(); ArrayList extensionReflectorTypes = new ArrayList(); ArrayList formatExtensionTypes = new ArrayList(); public WSConfig (WSConfig parent, object context) { if (parent == null) return; protocols = parent.protocols; wsdlHelpPage = parent.wsdlHelpPage; if (wsdlHelpPage != null) filePath = parent.filePath; else filePath = context as string; } static WSProtocol ParseProtocol (string protoName, out string error) { WSProtocol proto; error = null; try { proto = (WSProtocol) Enum.Parse (typeof (WSProtocol), protoName); } catch { error = "Invalid protocol name"; return 0; } return proto; } // Methods to modify configuration values public bool AddProtocol (string protoName, out string error) { if (protoName == "All") { error = "Invalid protocol name"; return false; } WSProtocol proto = ParseProtocol (protoName, out error); if (error != null) return false; protocols |= proto; return true; } public bool RemoveProtocol (string protoName, out string error) { if (protoName == "All") { error = "Invalid protocol name"; return false; } WSProtocol proto = ParseProtocol (protoName, out error); if (error != null) return false; protocols &= ~proto; return true; } public void ClearProtocol () { protocols = 0; } // Methods to query/get configuration public static bool IsSupported (WSProtocol proto) { return ((Instance.protocols & proto) == proto && (proto != 0) && (proto != WSProtocol.All)); } // Properties public string WsdlHelpPage { get { return wsdlHelpPage; } set { wsdlHelpPage = value; } } public string ConfigFilePath { get { return filePath; } set { filePath = value; } } static public WSConfig Instance { get { //TODO: use HttpContext to get the configuration if (instance != null) return instance; lock (typeof (WSConfig)) { if (instance != null) return instance; instance = (WSConfig) ConfigurationSettings.GetConfig ("system.web/webServices"); } return instance; } } public ArrayList ExtensionTypes { get { return extensionTypes; } } public ArrayList ExtensionImporterTypes { get { return extensionImporterTypes; } } public ArrayList ExtensionReflectorTypes { get { return extensionReflectorTypes; } } public ArrayList FormatExtensionTypes { get { return formatExtensionTypes; } } } enum WSExtensionGroup { High, Low } class WSExtensionConfig { Type type; int priority; WSExtensionGroup group; public Exception SetType (string typeName) { Exception exc = null; try { type = Type.GetType (typeName, true); } catch (Exception e) { exc = e; } return exc; } public Exception SetPriority (string prio) { if (prio == null || prio == "") return null; Exception exc = null; try { priority = Int32.Parse (prio); } catch (Exception e) { exc = e; } return exc; } public Exception SetGroup (string grp) { if (grp == null || grp == "") return null; Exception exc = null; try { group = (WSExtensionGroup) Int32.Parse (grp); if (group < WSExtensionGroup.High || group > WSExtensionGroup.Low) throw new ArgumentOutOfRangeException ("group", "Must be 0 or 1"); } catch (Exception e) { exc = e; } return exc; } // Getters public Type Type { get { return type; } } public int Priority { get { return priority; } } public WSExtensionGroup Group { get { return group; } } } class WebServicesConfigurationSectionHandler : IConfigurationSectionHandler { [MonoTODO("Some nodes not supported, see below")] public object Create (object parent, object context, XmlNode section) { WSConfig config = new WSConfig (parent as WSConfig, context); if (section.Attributes != null && section.Attributes.Count != 0) ThrowException ("Unrecognized attribute", section); XmlNodeList nodes = section.ChildNodes; foreach (XmlNode child in nodes) { XmlNodeType ntype = child.NodeType; if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment) continue; if (ntype != XmlNodeType.Element) ThrowException ("Only elements allowed", child); string name = child.Name; if (name == "protocols") { ConfigProtocols (child, config); continue; } if (name == "soapExtensionTypes") { ConfigSoapExtensionTypes (child, config.ExtensionTypes); continue; } if (name == "soapExtensionReflectorTypes") { ConfigSoapExtensionTypes (child, config.ExtensionReflectorTypes); continue; } if (name == "soapExtensionImporterTypes") { ConfigSoapExtensionTypes (child, config.ExtensionImporterTypes); continue; } if (name == "serviceDescriptionFormatExtensionTypes") { ConfigFormatExtensionTypes (child, config); continue; } if (name == "wsdlHelpGenerator") { string href = AttValue ("href", child, false); if (child.Attributes != null && child.Attributes.Count != 0) HandlersUtil.ThrowException ("Unrecognized attribute", child); config.ConfigFilePath = context as string; config.WsdlHelpPage = href; continue; } ThrowException ("Unexpected element", child); } return config; } static void ConfigProtocols (XmlNode section, WSConfig config) { if (section.Attributes != null && section.Attributes.Count != 0) ThrowException ("Unrecognized attribute", section); XmlNodeList nodes = section.ChildNodes; foreach (XmlNode child in nodes) { XmlNodeType ntype = child.NodeType; if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment) continue; if (ntype != XmlNodeType.Element) ThrowException ("Only elements allowed", child); string name = child.Name; string error; if (name == "add") { string protoName = AttValue ("name", child, false); if (child.Attributes != null && child.Attributes.Count != 0) HandlersUtil.ThrowException ("Unrecognized attribute", child); if (!config.AddProtocol (protoName, out error)) ThrowException (error, child); continue; } if (name == "remove") { string protoName = AttValue ("name", child, false); if (child.Attributes != null && child.Attributes.Count != 0) HandlersUtil.ThrowException ("Unrecognized attribute", child); if (!config.RemoveProtocol (protoName, out error)) ThrowException (error, child); continue; } if (name == "clear") { if (child.Attributes != null && child.Attributes.Count != 0) HandlersUtil.ThrowException ("Unrecognized attribute", child); config.ClearProtocol (); continue; } ThrowException ("Unexpected element", child); } } static void ConfigSoapExtensionTypes (XmlNode section, ArrayList extensions) { if (section.Attributes != null && section.Attributes.Count != 0) ThrowException ("Unrecognized attribute", section); XmlNodeList nodes = section.ChildNodes; foreach (XmlNode child in nodes) { XmlNodeType ntype = child.NodeType; if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment) continue; if (ntype != XmlNodeType.Element) ThrowException ("Only elements allowed", child); string name = child.Name; string error; if (name == "add") { string seType = AttValue ("type", child, false); string priority = AttValue ("priority", child); string group = AttValue ("group", child); if (child.Attributes != null && child.Attributes.Count != 0) HandlersUtil.ThrowException ("Unrecognized attribute", child); WSExtensionConfig wse = new WSExtensionConfig (); Exception e = wse.SetType (seType); if (e != null) ThrowException (e.Message, child); e = wse.SetPriority (priority); if (e != null) ThrowException (e.Message, child); e = wse.SetGroup (group); if (e != null) ThrowException (e.Message, child); extensions.Add (wse); continue; } ThrowException ("Unexpected element", child); } } static void ConfigFormatExtensionTypes (XmlNode section, WSConfig config) { if (section.Attributes != null && section.Attributes.Count != 0) ThrowException ("Unrecognized attribute", section); XmlNodeList nodes = section.ChildNodes; foreach (XmlNode child in nodes) { XmlNodeType ntype = child.NodeType; if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment) continue; if (ntype != XmlNodeType.Element) ThrowException ("Only elements allowed", child); string name = child.Name; string error; if (name == "add") { string typeName = AttValue ("name", child, false); if (child.Attributes != null && child.Attributes.Count != 0) HandlersUtil.ThrowException ("Unrecognized attribute", child); try { config.FormatExtensionTypes.Add (Type.GetType (typeName, true)); } catch (Exception e) { ThrowException (e.Message, child); } continue; } ThrowException ("Unexpected element", child); } } // To save some typing... static string AttValue (string name, XmlNode node, bool optional) { return HandlersUtil.ExtractAttributeValue (name, node, optional); } static string AttValue (string name, XmlNode node) { return HandlersUtil.ExtractAttributeValue (name, node, true); } static void ThrowException (string message, XmlNode node) { HandlersUtil.ThrowException (message, node); } // } class HandlersUtil { private HandlersUtil () { } static internal string ExtractAttributeValue (string attKey, XmlNode node) { return ExtractAttributeValue (attKey, node, false); } static internal string ExtractAttributeValue (string attKey, XmlNode node, bool optional) { if (node.Attributes == null) { if (optional) return null; ThrowException ("Required attribute not found: " + attKey, node); } XmlNode att = node.Attributes.RemoveNamedItem (attKey); if (att == null) { if (optional) return null; ThrowException ("Required attribute not found: " + attKey, node); } string value = att.Value; if (value == String.Empty) { string opt = optional ? "Optional" : "Required"; ThrowException (opt + " attribute is empty: " + attKey, node); } return value; } static internal void ThrowException (string msg, XmlNode node) { if (node != null && node.Name != String.Empty) msg = msg + " (node name: " + node.Name + ") "; throw new ConfigurationException (msg, node); } } }