/// <summary> /// Creates an XML string containing an unmerged view of the <see cref="ConfigurationSection"/> object as a single section to write to a file. /// </summary> /// <returns> /// An XML string containing an unmerged view of the <see cref="ConfigurationSection"/> object. /// </returns> /// <param name="parentElement">The <see cref="ConfigurationElement"/> instance to use as the parent when performing the un-merge.</param> /// <param name="name">The name of the section to create.</param> /// <param name="saveMode">The <see cref="ConfigurationSaveMode"/> instance to use when writing to a string.</param> protected override string SerializeSection(ConfigurationElement parentElement, string name, ConfigurationSaveMode saveMode) { if ((object)m_sections != null) { const string tempRoot = "__tempRoot__"; using (BlockAllocatedMemoryStream stream = new BlockAllocatedMemoryStream()) { XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8); writer.Indentation = 2; writer.Formatting = Formatting.Indented; // Add a temporary root so that indentation is at the desired level writer.WriteStartElement(tempRoot); writer.WriteStartElement(name); foreach (string section in m_sections.Keys) { CategorizedSettingsElementCollection categorySettings = this[section]; // Add category section writer.WriteStartElement(section); // Write each category value foreach (CategorizedSettingsElement categorySetting in categorySettings) { // <add name="TestConfigParam" value="-1.0" description="Parameter description." encrypted="false" scope="User"/> writer.WriteStartElement("add"); writer.WriteAttributeString("name", categorySetting.Name); writer.WriteAttributeString("value", categorySetting.SerializedValue); writer.WriteAttributeString("description", categorySetting.Description ?? ""); writer.WriteAttributeString("encrypted", categorySetting.Encrypted.ToString()); if (categorySetting.Scope == SettingScope.User) { writer.WriteAttributeString("scope", categorySetting.Scope.ToString()); } writer.WriteEndElement(); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); writer.Flush(); string settings = Encoding.UTF8.GetString(stream.ToArray()); // Remove temporary root return(settings.Replace(string.Format("<{0}>", tempRoot), "").Replace(string.Format("</{0}>", tempRoot), "")); } } return(base.SerializeSection(parentElement, name, saveMode)); }
/// <summary> /// Gets the <see cref="CategorizedSettingsElementCollection"/> object representing settings under the specified category name. /// </summary> /// <param name="name">Name of the category whose settings are to be retrieved.</param> /// <returns><see cref="CategorizedSettingsElementCollection"/> object with settings under the specified category name.</returns> /// <exception cref="ArgumentNullException"><paramref name="name"/> is null or empty string.</exception> public new CategorizedSettingsElementCollection this[string name] { get { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } // We will add the requested category to the default properties collection, so that when // the settings are saved off to the config file, all of the categories under which // settings may be saved are processed and saved to the config file. This is essentially // doing what marking a property with the <ConfigurationProperty()> attribute does. // Make the first letter of category name lower case, if not already. char[] nameChars = name.ToCharArray(); nameChars[0] = char.ToLower(nameChars[0]); // Do not allow spaces in the name so that underlying .Net configuration API does not break. name = (new string(nameChars)).RemoveWhiteSpace(); ConfigurationProperty configProperty = new ConfigurationProperty(name, typeof(CategorizedSettingsElementCollection)); CategorizedSettingsElementCollection settingsCategory = null; if ((object)m_sections == null) { base.Properties.Add(configProperty); if ((object)base[configProperty] != null) { settingsCategory = (CategorizedSettingsElementCollection) base[configProperty]; settingsCategory.Name = name; settingsCategory.Section = this; settingsCategory.SetCryptoKey(m_cryptoKey); } } else { settingsCategory = m_sections.GetOrAdd(name, sectionName => { base.Properties.Add(configProperty); CategorizedSettingsElementCollection settings = new CategorizedSettingsElementCollection { Name = sectionName, Section = this, }; settings.SetCryptoKey(m_cryptoKey); Modified = true; return(settings); }); } return(settingsCategory); } }
/// <summary> /// Removes the specified category name including its associated settings. /// </summary> /// <param name="name">Name of the category to be removed.</param> /// <exception cref="ArgumentNullException"><paramref name="name"/> is null or empty string.</exception> public void Remove(string name) { // Get the category to be removed. CategorizedSettingsElementCollection settingsCategory = this[name]; // Remove existing category settings. while (settingsCategory.GetEnumerator().MoveNext()) { settingsCategory.RemoveAt(0); } // Remove category from property bag. if ((object)m_sections == null) { base.Properties.Remove(settingsCategory.Name); } else { m_sections.Remove(settingsCategory.Name); } }
/// <summary> /// Reads XML from the configuration file. /// </summary> /// <param name="reader">The <see cref="System.Xml.XmlReader"/> object, which reads from the configuration file.</param> protected override void DeserializeSection(XmlReader reader) { using (BlockAllocatedMemoryStream configSectionStream = new BlockAllocatedMemoryStream()) { XmlDocument configSection = new XmlDocument(); configSection.Load(reader); configSection.Save(configSectionStream); // Adds all the categories that are under the categorizedSettings section of the configuration file // to the property collection. Again, this is essentially doing what marking a property with the // <ConfigurationProperty()> attribute does. If this is not done, then an exception will be raised // when the category elements are being deserialized. if ((object)configSection.DocumentElement != null) { XmlNodeList categories = configSection.DocumentElement.SelectNodes("*"); if ((object)categories != null) { foreach (XmlNode category in categories) { ConfigurationProperty configProperty = new ConfigurationProperty(category.Name, typeof(CategorizedSettingsElementCollection)); base.Properties.Add(configProperty); if ((object)m_sections != null) { CategorizedSettingsElementCollection settingsCategory = new CategorizedSettingsElementCollection { Name = category.Name, Section = this, }; settingsCategory.SetCryptoKey(m_cryptoKey); m_sections.Add(category.Name, settingsCategory); // Read all elements within this category section XmlNodeList elements = category.SelectNodes("*"); SettingScope scope; if ((object)elements != null) { foreach (XmlNode element in elements) { CategorizedSettingsElement categorySetting = new CategorizedSettingsElement(settingsCategory); categorySetting.Name = element.GetAttributeValue("name"); categorySetting.Value = element.GetAttributeValue("value"); categorySetting.Description = element.GetAttributeValue("description") ?? ""; categorySetting.Encrypted = element.GetAttributeValue("encrypted").ToNonNullNorWhiteSpace("false").ParseBoolean(); if (Enum.TryParse(element.GetAttributeValue("scope").ToNonNullNorWhiteSpace("Application"), out scope)) categorySetting.Scope = scope; else categorySetting.Scope = SettingScope.Application; settingsCategory.Add(categorySetting); } } } } } } m_sectionLoaded = true; if ((object)m_sections == null) { configSectionStream.Seek(0, SeekOrigin.Begin); base.DeserializeSection(XmlReader.Create(configSectionStream)); } } }
/// <summary> /// Gets the <see cref="CategorizedSettingsElementCollection"/> object representing settings under the specified category name. /// </summary> /// <param name="name">Name of the category whose settings are to be retrieved.</param> /// <returns><see cref="CategorizedSettingsElementCollection"/> object with settings under the specified category name.</returns> /// <exception cref="ArgumentNullException"><paramref name="name"/> is null or empty string.</exception> public new CategorizedSettingsElementCollection this[string name] { get { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); // We will add the requested category to the default properties collection, so that when // the settings are saved off to the config file, all of the categories under which // settings may be saved are processed and saved to the config file. This is essentially // doing what marking a property with the <ConfigurationProperty()> attribute does. // Make the first letter of category name lower case, if not already. char[] nameChars = name.ToCharArray(); nameChars[0] = char.ToLower(nameChars[0]); // Do not allow spaces in the name so that underlying .Net configuration API does not break. name = (new string(nameChars)).RemoveWhiteSpace(); ConfigurationProperty configProperty = new ConfigurationProperty(name, typeof(CategorizedSettingsElementCollection)); CategorizedSettingsElementCollection settingsCategory = null; if ((object)m_sections == null) { base.Properties.Add(configProperty); if ((object)base[configProperty] != null) { settingsCategory = (CategorizedSettingsElementCollection)base[configProperty]; settingsCategory.Name = name; settingsCategory.Section = this; settingsCategory.SetCryptoKey(m_cryptoKey); } } else { settingsCategory = m_sections.GetOrAdd(name, sectionName => { base.Properties.Add(configProperty); CategorizedSettingsElementCollection settings = new CategorizedSettingsElementCollection { Name = sectionName, Section = this, }; settings.SetCryptoKey(m_cryptoKey); Modified = true; return settings; }); } return settingsCategory; } }
/// <summary> /// Reads XML from the configuration file. /// </summary> /// <param name="reader">The <see cref="System.Xml.XmlReader"/> object, which reads from the configuration file.</param> protected override void DeserializeSection(XmlReader reader) { using (BlockAllocatedMemoryStream configSectionStream = new BlockAllocatedMemoryStream()) { XmlDocument configSection = new XmlDocument(); configSection.Load(reader); configSection.Save(configSectionStream); // Adds all the categories that are under the categorizedSettings section of the configuration file // to the property collection. Again, this is essentially doing what marking a property with the // <ConfigurationProperty()> attribute does. If this is not done, then an exception will be raised // when the category elements are being deserialized. if ((object)configSection.DocumentElement != null) { XmlNodeList categories = configSection.DocumentElement.SelectNodes("*"); if ((object)categories != null) { foreach (XmlNode category in categories) { ConfigurationProperty configProperty = new ConfigurationProperty(category.Name, typeof(CategorizedSettingsElementCollection)); base.Properties.Add(configProperty); if ((object)m_sections != null) { CategorizedSettingsElementCollection settingsCategory = new CategorizedSettingsElementCollection { Name = category.Name, Section = this, }; settingsCategory.SetCryptoKey(m_cryptoKey); m_sections.Add(category.Name, settingsCategory); // Read all elements within this category section XmlNodeList elements = category.SelectNodes("*"); SettingScope scope; if ((object)elements != null) { foreach (XmlNode element in elements) { CategorizedSettingsElement categorySetting = new CategorizedSettingsElement(settingsCategory); categorySetting.Name = element.GetAttributeValue("name"); categorySetting.Value = element.GetAttributeValue("value"); categorySetting.Description = element.GetAttributeValue("description") ?? ""; categorySetting.Encrypted = element.GetAttributeValue("encrypted").ToNonNullNorWhiteSpace("false").ParseBoolean(); if (Enum.TryParse(element.GetAttributeValue("scope").ToNonNullNorWhiteSpace("Application"), out scope)) { categorySetting.Scope = scope; } else { categorySetting.Scope = SettingScope.Application; } settingsCategory.Add(categorySetting); } } } } } } m_sectionLoaded = true; if ((object)m_sections == null) { configSectionStream.Seek(0, SeekOrigin.Begin); base.DeserializeSection(XmlReader.Create(configSectionStream)); } } }
/// <summary> /// Required by the configuration API and is for internal use only. /// </summary> internal CategorizedSettingsElement(CategorizedSettingsElementCollection category, string name) { m_category = category; this.Name = name; m_cryptoKey = DefaultCryptoKey; }
/// <summary> /// Required by the configuration API and is for internal use only. /// </summary> internal CategorizedSettingsElement(CategorizedSettingsElementCollection category) : this(category, "") { }