//******************************************************************************************************
// ConfigurationFile.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/eclipse-1.0.php
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 04/12/2006 - Pinal C. Patel
// Generated original version of source code.
// 11/14/2006 - Pinal C. Patel
// Modified the ValidateConfigurationFile to save the config file only it was modified.
// 12/12/2006 - Pinal C. Patel
// Wrote the TrimEnd function that is being used for initialized the Configuration object.
// 08/20/2007 - Darrell Zuercher
// Edited code comments.
// 09/22/2008 - Pinal C. Patel
// Converted code to C#.
// 09/29/2008 - Pinal C. Patel
// Reviewed code comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 09/29/2008 - Pinal C. Patel
// Added new CurrentWeb and CurrentWin static properties to get the configuration file for a
// specific type of application (i.e. Web or Windows).
// Modified GetConfiguration() to remove dependency on HttpContext.Current to avoid exception in
// async web application operations where HttpContext.Current is null.
// 04/20/2010 - Pinal C. Patel
// Added static Open() method as the only way of retrieving a ConfigurationFile instance.
// Added internal UserConfigurationFile class for accessing and updating user scope settings.
// 07/01/2010 - Pinal C. Patel
// Removed FileName, AppSettings and ConnectionStrings proxy properties and replaced them with
// new Configuration property to allow for full access to the application configuration.
// 11/26/2010 - Pinal C. Patel
// Updated usage example to include user-scope setting sample.
// 12/05/2010 - Pinal C. Patel
// Added Culture property that can be used for specifying a culture to use for value conversion.
// 01/04/2011 - J. Ritchie Carroll
// Modified culture to default to InvariantCulture for English style parsing defaults.
// 04/07/2011 - J. Ritchie Carroll
// Added a Reload() method to reload the configuration file settings and a
// RestoreDefaultUserSettings() method to restore the default user settings.
// 12/12/2011 - J. Ritchie Carroll
// Added synchronization to save methods such that saves from multiple threads will not
// cause issues when lots of new settings are being added.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Concurrent;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Xml;
using GSF.IO;
using GSF.Xml;
namespace GSF.Configuration
{
/// <summary>
/// Represents a configuration file of a Windows or Web application.
/// </summary>
/// <example>
/// This example shows how to save and read settings from the config file:
/// <code>
/// using System;
/// using System.Configuration;
/// using GSF;
/// using GSF.Configuration;
///
/// class Program
/// {
/// static void Main(string[] args)
/// {
/// // Get the application config file.
/// ConfigurationFile config = ConfigurationFile.Current;
///
/// // Get the sections of config file.
/// CategorizedSettingsElementCollection startup = config.Settings["Startup"];
/// CategorizedSettingsElementCollection passwords = config.Settings["Passwords"];
/// CategorizedSettingsElementCollection monitoring = config.Settings["Monitoring"];
/// KeyValueConfigurationCollection appSettings = config.Configuration.AppSettings.Settings;
/// ConnectionStringSettingsCollection connStrings = config.Configuration.ConnectionStrings.ConnectionStrings;
///
/// // Add settings to the config file under the "appSettings" section.
/// appSettings.Add("SaveSettingOnExit", true.ToString());
/// // Add settings to the config file under the "connectionStrings" section.
/// connStrings.Add(new ConnectionStringSettings("DevSql", "Server=SqlServer;Database=Sandbox;Trusted_Connection=True"));
/// // Add settings to the config (if they don't exist) under a custom "monitoring" section.
/// monitoring.Add("RefreshInterval", 5, "Interval in seconds at which the Monitor screen is to be refreshed.");
/// monitoring.Add("MessagesSnapshot", 30000, "Maximum messages length to be displayed on the Monitor screen.");
/// // Add password to the config file encrypted (if it doesn't exist) under a custom "passwords" section.
/// passwords.Add("Admin", "Adm1nP4ss", "Password used for performing administrative tasks.", true);
/// // Add user-scope setting to the config (if it doesn't exist) under a custom "startup" section.
/// startup.Add("Theme", "Default", "Application theme to use for the session.", false, SettingScope.User);
/// config.Save(); // Save settings to the config file.
///
/// // Read saved settings from the config file.
/// bool saveSettingsOnExit = appSettings["SaveSettingOnExit"].Value.ParseBoolean();
/// string devConnectionString = connStrings["DevSql"].ConnectionString;
/// string appTheme = startup["Theme"].Value;
/// string adminPassword = passwords["Admin"].Value;
/// int refreshInterval = monitoring["RefreshInterval"].ValueAsInt32();
/// int messagesSnapshot = monitoring["MessagesSnapshot"].ValueAsInt32();
///
/// // Print the retrieved settings to the console.
/// Console.WriteLine("SaveSettingOnExit = {0}", saveSettingsOnExit);
/// Console.WriteLine("DevSql = {0}", devConnectionString);
/// Console.WriteLine("Theme = {0}", appTheme);
/// Console.WriteLine("Admin = {0}", adminPassword);
/// Console.WriteLine("RefreshInterval = {0}", refreshInterval);
/// Console.WriteLine("MessagesSnapshot = {0}", messagesSnapshot);
///
/// Console.ReadLine();
/// }
/// }
/// </code>
/// This example shows the content of the config file from the sample code above:
/// <code>
/// <![CDATA[
/// <?xml version="1.0" encoding="utf-8"?>
/// <configuration>
/// <configSections>
/// <section name="categorizedSettings" type="GSF.Configuration.CategorizedSettingsSection, GSF.Core" />
/// </configSections>
/// <appSettings>
/// <add key="SaveSettingOnExit" value="True" />
/// </appSettings>
/// <categorizedSettings>
/// <startup>
/// <add name="Theme" value="Default" description="Application theme to use for the session."
/// encrypted="false" scope="User" />
/// </startup>
/// <passwords>
/// <add name="Admin" value="C+0j6fE/N0Q9b5xaeDKgvRmSeY9zJkO1EQCr7cHoG3x24tztlbBB54PfWsuMGXc/"
/// description="Password used for performing administrative tasks."
/// encrypted="true" />
/// </passwords>
/// <monitoring>
/// <add name="RefreshInterval" value="5" description="Interval in seconds at which the Monitor screen is to be refreshed."
/// encrypted="false" />
/// <add name="MessagesSnapshot" value="30000" description="Maximum messages length to be displayed on the Monitor screen."
/// encrypted="false" />
/// </monitoring>
/// </categorizedSettings>
/// <connectionStrings>
/// <add name="DevSql" connectionString="Server=SqlServer;Database=Sandbox;Trusted_Connection=True" />
/// </connectionStrings>
/// </configuration>
/// ]]>
/// </code>
/// </example>
/// <seealso cref="CategorizedSettingsSection"/>
/// <seealso cref="CategorizedSettingsElement"/>
/// <seealso cref="CategorizedSettingsElementCollection"/>
// Since each instance of this class is statically cached for the process lifetime, IDisposable is not implemented so that
// the instance will not be inadvertently disposed
public class ConfigurationFile
{
#region [ Members ]
// Nested Types
internal class UserConfigurationFile
{
private readonly string m_fileName;
private readonly XmlDocument m_settings;
private bool m_settingsModified;
private const string RootNode = "settings";
private const string Filename = "Settings.xml";
public UserConfigurationFile()
{
m_settings = new XmlDocument();
m_fileName = Path.Combine(FilePath.GetApplicationDataFolder(), Filename);
if (File.Exists(m_fileName))
{
// Load existing settings.
m_settings.Load(m_fileName);
}
else
{
// Create new settings file.
m_settings.AppendChild(m_settings.CreateNode(XmlNodeType.XmlDeclaration, null, null));
m_settings.AppendChild(m_settings.CreateElement(RootNode));
}
}
public string FileName
{
get
{
return m_fileName;
}
}
public void Save(bool force)
{
if (force || m_settingsModified)
{
// Create directory if missing.
string folder = FilePath.GetDirectoryName(m_fileName);
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
// Save settings to the file.
m_settings.Save(m_fileName);
}
}
public void Write(string category, string name, string value)
{
XmlNode node = GetSetting(category, name);
if ((object)node != null)
{
// Setting exists so update it.
node.SetAttributeValue("value", value);
}
else
{
// Setting doesn't exist so add it.
XmlNode setting = m_settings.CreateElement("add");
setting.SetAttributeValue("name", name);
setting.SetAttributeValue("value", value);
m_settings.GetXmlNode(category).AppendChild(setting);
}
m_settingsModified = true;
}
public string Read(string category, string name, string defaultValue)
{
XmlNode node = GetSetting(category, name);
if ((object)node != null)
// Setting exists so return its value.
return node.Attributes["value"].Value;
else
// Setting doesn't exist so return the default.
return defaultValue;
}
public XmlNode GetSetting(string category, string name)
{
return m_settings.SelectSingleNode(string.Format("{0}/{1}/add[@name='{2}']", RootNode, category, name));
}
}
// Constants
private const string CustomSectionName = "categorizedSettings";
private const string CustomSectionType = "GSF.Configuration.CategorizedSettingsSection, GSF.Core";
// Fields
private string m_cryptoKey;
private CultureInfo m_culture;
private System.Configuration.Configuration m_configuration;
private UserConfigurationFile m_userConfiguration;
private readonly object m_queuedConfigurationSavePending;
private readonly AutoResetEvent m_configurationSaveComplete;
#endregion
#region [ Constructors ]
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationFile"/> class.
/// </summary>
internal ConfigurationFile(string configFilePath)
{
m_culture = CultureInfo.InvariantCulture;
m_queuedConfigurationSavePending = new object();
m_configurationSaveComplete = new AutoResetEvent(true);
m_configuration = GetConfiguration(configFilePath);
if (m_configuration.HasFile)
ValidateConfigurationFile(m_configuration.FilePath);
else
CreateConfigurationFile(m_configuration.FilePath);
m_configuration = GetConfiguration(configFilePath);
m_userConfiguration = new UserConfigurationFile();
}
#endregion
#region [ Properties ]
/// <summary>
/// Gets or sets the <see cref="CultureInfo"/> to use for the conversion of setting values to and from <see cref="string"/>.
/// </summary>
public CultureInfo Culture
{
get
{
return m_culture;
}
set
{
if ((object)value != null)
m_culture = value;
else
m_culture = CultureInfo.InvariantCulture;
}
}
/// <summary>
/// Get the underlying <see cref="System.Configuration.Configuration"/> that can be accessed using this <see cref="ConfigurationFile"/> object.
/// </summary>
public System.Configuration.Configuration Configuration
{
get
{
return m_configuration;
}
}
/// <summary>
/// Gets the <see cref="CategorizedSettingsSection"/> object representing settings under the "categorizedSettings" section of the config file.
/// </summary>
public CategorizedSettingsSection Settings
{
get
{
CategorizedSettingsSection settings = (CategorizedSettingsSection)m_configuration.GetSection(CustomSectionName);
settings.File = this;
settings.SetCryptoKey(m_cryptoKey);
return settings;
}
}
/// <summary>
/// Gets the <see cref="UserConfigurationFile"/> where user specific settings are saved.
/// </summary>
internal UserConfigurationFile UserSettings
{
get
{
return m_userConfiguration;
}
}
#endregion
#region [ Methods ]
/// <summary>
/// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the configuration file that it represents.
/// </summary>
public void Save()
{
Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the configuration file that it represents.
/// </summary>
/// <param name="saveMode">One of the <see cref="ConfigurationSaveMode"/> values.</param>
public void Save(ConfigurationSaveMode saveMode)
{
// Since the static open method always returns the same instance for the same configuration files,
// synchronizing the instance will sync all saves.
ThreadPool.QueueUserWorkItem(QueueConfigurationSave, saveMode);
}
private void QueueConfigurationSave(object state)
{
// Queue up a configuration save unless another thread has already requested one
if (Monitor.TryEnter(m_queuedConfigurationSavePending))
{
try
{
// Queue new configuration save after waiting for any prior save to complete
if (m_configurationSaveComplete.WaitOne())
ThreadPool.QueueUserWorkItem(ExecuteConfigurationSave, state);
}
finally
{
Monitor.Exit(m_queuedConfigurationSavePending);
}
}
}
private void ExecuteConfigurationSave(object state)
{
try
{
// Perform configuration save
ConfigurationSaveMode saveMode = (ConfigurationSaveMode)state;
m_configuration.Save(saveMode);
m_userConfiguration.Save(saveMode == ConfigurationSaveMode.Full);
}
finally
{
// Release waiting thread
if (m_configurationSaveComplete != null)
m_configurationSaveComplete.Set();
}
}
/// <summary>
/// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the specified configuration file.
/// </summary>
/// <param name="fileName">The path and file name to save the configuration file to.</param>
public void SaveAs(string fileName)
{
m_configuration.SaveAs(fileName);
}
/// <summary>
/// Reloads the current configuration settings from the configuration file that the <see cref="ConfigurationFile"/> represents.
/// </summary>
public void Reload()
{
m_configuration = GetConfiguration(m_configuration.FilePath);
m_userConfiguration = new UserConfigurationFile();
}
/// <summary>
/// Restores all the default settings for <see cref="SettingScope.User"/> scoped settings.
/// </summary>
public void RestoreDefaultUserSettings()
{
if ((object)m_userConfiguration != null)
{
string fileName = m_userConfiguration.FileName;
if (File.Exists(fileName))
File.Delete(fileName);
m_userConfiguration = new UserConfigurationFile();
}
}
/// <summary>
/// Sets the key to be used for encrypting and decrypting values of <see cref="Settings"/>.
/// </summary>
/// <param name="cryptoKey">New crypto key.</param>
public void SetCryptoKey(string cryptoKey)
{
m_cryptoKey = cryptoKey;
}
private System.Configuration.Configuration GetConfiguration(string configFilePath)
{
ApplicationType appType = Common.GetApplicationType();
System.Configuration.Configuration configuration = null;
if ((object)configFilePath != null)
{
if (string.IsNullOrEmpty(configFilePath) || string.Compare(FilePath.GetExtension(configFilePath), ".config", true) == 0)
{
// PCP - 12/12/2006: Using the TrimEnd function to get the correct value that needs to be passed
// to the method call for getting the Configuration object. The previous method (String.TrimEnd())
// yielded incorrect output resulting in the Configuration object not being initialized correctly.
switch (appType)
{
case ApplicationType.WindowsCui:
case ApplicationType.WindowsGui:
configuration = ConfigurationManager.OpenExeConfiguration(TrimEnd(configFilePath, ".config").EnsureEnd(".exe"));
break;
case ApplicationType.Web:
if (string.IsNullOrEmpty(configFilePath))
configFilePath = HostingEnvironment.ApplicationVirtualPath;
configuration = WebConfigurationManager.OpenWebConfiguration(TrimEnd(configFilePath, "web.config"));
break;
}
}
else
{
throw (new ArgumentException("Path of configuration file must be either empty or end in \'.config\'"));
}
}
else
{
throw (new ArgumentNullException("configFilePath", "Path of configuration file path cannot be null"));
}
return configuration;
}
private void CreateConfigurationFile(string configFilePath)
{
if (!string.IsNullOrEmpty(configFilePath))
{
Lines 1–500 of 618. Load more
//****************************************************************************************************** // ConfigurationFile.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 04/12/2006 - Pinal C. Patel // Generated original version of source code. // 11/14/2006 - Pinal C. Patel // Modified the ValidateConfigurationFile to save the config file only it was modified. // 12/12/2006 - Pinal C. Patel // Wrote the TrimEnd function that is being used for initialized the Configuration object. // 08/20/2007 - Darrell Zuercher // Edited code comments. // 09/22/2008 - Pinal C. Patel // Converted code to C#. // 09/29/2008 - Pinal C. Patel // Reviewed code comments. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 09/29/2008 - Pinal C. Patel // Added new CurrentWeb and CurrentWin static properties to get the configuration file for a // specific type of application (i.e. Web or Windows). // Modified GetConfiguration() to remove dependency on HttpContext.Current to avoid exception in // async web application operations where HttpContext.Current is null. // 04/20/2010 - Pinal C. Patel // Added static Open() method as the only way of retrieving a ConfigurationFile instance. // Added internal UserConfigurationFile class for accessing and updating user scope settings. // 07/01/2010 - Pinal C. Patel // Removed FileName, AppSettings and ConnectionStrings proxy properties and replaced them with // new Configuration property to allow for full access to the application configuration. // 11/26/2010 - Pinal C. Patel // Updated usage example to include user-scope setting sample. // 12/05/2010 - Pinal C. Patel // Added Culture property that can be used for specifying a culture to use for value conversion. // 01/04/2011 - J. Ritchie Carroll // Modified culture to default to InvariantCulture for English style parsing defaults. // 04/07/2011 - J. Ritchie Carroll // Added a Reload() method to reload the configuration file settings and a // RestoreDefaultUserSettings() method to restore the default user settings. // 12/12/2011 - J. Ritchie Carroll // Added synchronization to save methods such that saves from multiple threads will not // cause issues when lots of new settings are being added. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Concurrent; using System.Configuration; using System.Globalization; using System.IO; using System.Text; using System.Threading; using System.Web.Configuration; using System.Web.Hosting; using System.Xml; using GSF.IO; using GSF.Xml; namespace GSF.Configuration { /// <summary> /// Represents a configuration file of a Windows or Web application. /// </summary> /// <example> /// This example shows how to save and read settings from the config file: /// <code> /// using System; /// using System.Configuration; /// using GSF; /// using GSF.Configuration; /// /// class Program /// { /// static void Main(string[] args) /// { /// // Get the application config file. /// ConfigurationFile config = ConfigurationFile.Current; /// /// // Get the sections of config file. /// CategorizedSettingsElementCollection startup = config.Settings["Startup"]; /// CategorizedSettingsElementCollection passwords = config.Settings["Passwords"]; /// CategorizedSettingsElementCollection monitoring = config.Settings["Monitoring"]; /// KeyValueConfigurationCollection appSettings = config.Configuration.AppSettings.Settings; /// ConnectionStringSettingsCollection connStrings = config.Configuration.ConnectionStrings.ConnectionStrings; /// /// // Add settings to the config file under the "appSettings" section. /// appSettings.Add("SaveSettingOnExit", true.ToString()); /// // Add settings to the config file under the "connectionStrings" section. /// connStrings.Add(new ConnectionStringSettings("DevSql", "Server=SqlServer;Database=Sandbox;Trusted_Connection=True")); /// // Add settings to the config (if they don't exist) under a custom "monitoring" section. /// monitoring.Add("RefreshInterval", 5, "Interval in seconds at which the Monitor screen is to be refreshed."); /// monitoring.Add("MessagesSnapshot", 30000, "Maximum messages length to be displayed on the Monitor screen."); /// // Add password to the config file encrypted (if it doesn't exist) under a custom "passwords" section. /// passwords.Add("Admin", "Adm1nP4ss", "Password used for performing administrative tasks.", true); /// // Add user-scope setting to the config (if it doesn't exist) under a custom "startup" section. /// startup.Add("Theme", "Default", "Application theme to use for the session.", false, SettingScope.User); /// config.Save(); // Save settings to the config file. /// /// // Read saved settings from the config file. /// bool saveSettingsOnExit = appSettings["SaveSettingOnExit"].Value.ParseBoolean(); /// string devConnectionString = connStrings["DevSql"].ConnectionString; /// string appTheme = startup["Theme"].Value; /// string adminPassword = passwords["Admin"].Value; /// int refreshInterval = monitoring["RefreshInterval"].ValueAsInt32(); /// int messagesSnapshot = monitoring["MessagesSnapshot"].ValueAsInt32(); /// /// // Print the retrieved settings to the console. /// Console.WriteLine("SaveSettingOnExit = {0}", saveSettingsOnExit); /// Console.WriteLine("DevSql = {0}", devConnectionString); /// Console.WriteLine("Theme = {0}", appTheme); /// Console.WriteLine("Admin = {0}", adminPassword); /// Console.WriteLine("RefreshInterval = {0}", refreshInterval); /// Console.WriteLine("MessagesSnapshot = {0}", messagesSnapshot); /// /// Console.ReadLine(); /// } /// } /// </code> /// This example shows the content of the config file from the sample code above: /// <code> /// <![CDATA[ /// <?xml version="1.0" encoding="utf-8"?> /// <configuration> /// <configSections> /// <section name="categorizedSettings" type="GSF.Configuration.CategorizedSettingsSection, GSF.Core" /> /// </configSections> /// <appSettings> /// <add key="SaveSettingOnExit" value="True" /> /// </appSettings> /// <categorizedSettings> /// <startup> /// <add name="Theme" value="Default" description="Application theme to use for the session." /// encrypted="false" scope="User" /> /// </startup> /// <passwords> /// <add name="Admin" value="C+0j6fE/N0Q9b5xaeDKgvRmSeY9zJkO1EQCr7cHoG3x24tztlbBB54PfWsuMGXc/" /// description="Password used for performing administrative tasks." /// encrypted="true" /> /// </passwords> /// <monitoring> /// <add name="RefreshInterval" value="5" description="Interval in seconds at which the Monitor screen is to be refreshed." /// encrypted="false" /> /// <add name="MessagesSnapshot" value="30000" description="Maximum messages length to be displayed on the Monitor screen." /// encrypted="false" /> /// </monitoring> /// </categorizedSettings> /// <connectionStrings> /// <add name="DevSql" connectionString="Server=SqlServer;Database=Sandbox;Trusted_Connection=True" /> /// </connectionStrings> /// </configuration> /// ]]> /// </code> /// </example> /// <seealso cref="CategorizedSettingsSection"/> /// <seealso cref="CategorizedSettingsElement"/> /// <seealso cref="CategorizedSettingsElementCollection"/> // Since each instance of this class is statically cached for the process lifetime, IDisposable is not implemented so that // the instance will not be inadvertently disposed public class ConfigurationFile { #region [ Members ] // Nested Types internal class UserConfigurationFile { private readonly string m_fileName; private readonly XmlDocument m_settings; private bool m_settingsModified; private const string RootNode = "settings"; private const string Filename = "Settings.xml"; public UserConfigurationFile() { m_settings = new XmlDocument(); m_fileName = Path.Combine(FilePath.GetApplicationDataFolder(), Filename); if (File.Exists(m_fileName)) { // Load existing settings. m_settings.Load(m_fileName); } else { // Create new settings file. m_settings.AppendChild(m_settings.CreateNode(XmlNodeType.XmlDeclaration, null, null)); m_settings.AppendChild(m_settings.CreateElement(RootNode)); } } public string FileName { get { return m_fileName; } } public void Save(bool force) { if (force || m_settingsModified) { // Create directory if missing. string folder = FilePath.GetDirectoryName(m_fileName); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); // Save settings to the file. m_settings.Save(m_fileName); } } public void Write(string category, string name, string value) { XmlNode node = GetSetting(category, name); if ((object)node != null) { // Setting exists so update it. node.SetAttributeValue("value", value); } else { // Setting doesn't exist so add it. XmlNode setting = m_settings.CreateElement("add"); setting.SetAttributeValue("name", name); setting.SetAttributeValue("value", value); m_settings.GetXmlNode(category).AppendChild(setting); } m_settingsModified = true; } public string Read(string category, string name, string defaultValue) { XmlNode node = GetSetting(category, name); if ((object)node != null) // Setting exists so return its value. return node.Attributes["value"].Value; else // Setting doesn't exist so return the default. return defaultValue; } public XmlNode GetSetting(string category, string name) { return m_settings.SelectSingleNode(string.Format("{0}/{1}/add[@name='{2}']", RootNode, category, name)); } } // Constants private const string CustomSectionName = "categorizedSettings"; private const string CustomSectionType = "GSF.Configuration.CategorizedSettingsSection, GSF.Core"; // Fields private string m_cryptoKey; private CultureInfo m_culture; private System.Configuration.Configuration m_configuration; private UserConfigurationFile m_userConfiguration; private readonly object m_queuedConfigurationSavePending; private readonly AutoResetEvent m_configurationSaveComplete; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="ConfigurationFile"/> class. /// </summary> internal ConfigurationFile(string configFilePath) { m_culture = CultureInfo.InvariantCulture; m_queuedConfigurationSavePending = new object(); m_configurationSaveComplete = new AutoResetEvent(true); m_configuration = GetConfiguration(configFilePath); if (m_configuration.HasFile) ValidateConfigurationFile(m_configuration.FilePath); else CreateConfigurationFile(m_configuration.FilePath); m_configuration = GetConfiguration(configFilePath); m_userConfiguration = new UserConfigurationFile(); } #endregion #region [ Properties ] /// <summary> /// Gets or sets the <see cref="CultureInfo"/> to use for the conversion of setting values to and from <see cref="string"/>. /// </summary> public CultureInfo Culture { get { return m_culture; } set { if ((object)value != null) m_culture = value; else m_culture = CultureInfo.InvariantCulture; } } /// <summary> /// Get the underlying <see cref="System.Configuration.Configuration"/> that can be accessed using this <see cref="ConfigurationFile"/> object. /// </summary> public System.Configuration.Configuration Configuration { get { return m_configuration; } } /// <summary> /// Gets the <see cref="CategorizedSettingsSection"/> object representing settings under the "categorizedSettings" section of the config file. /// </summary> public CategorizedSettingsSection Settings { get { CategorizedSettingsSection settings = (CategorizedSettingsSection)m_configuration.GetSection(CustomSectionName); settings.File = this; settings.SetCryptoKey(m_cryptoKey); return settings; } } /// <summary> /// Gets the <see cref="UserConfigurationFile"/> where user specific settings are saved. /// </summary> internal UserConfigurationFile UserSettings { get { return m_userConfiguration; } } #endregion #region [ Methods ] /// <summary> /// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the configuration file that it represents. /// </summary> public void Save() { Save(ConfigurationSaveMode.Modified); } /// <summary> /// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the configuration file that it represents. /// </summary> /// <param name="saveMode">One of the <see cref="ConfigurationSaveMode"/> values.</param> public void Save(ConfigurationSaveMode saveMode) { // Since the static open method always returns the same instance for the same configuration files, // synchronizing the instance will sync all saves. ThreadPool.QueueUserWorkItem(QueueConfigurationSave, saveMode); } private void QueueConfigurationSave(object state) { // Queue up a configuration save unless another thread has already requested one if (Monitor.TryEnter(m_queuedConfigurationSavePending)) { try { // Queue new configuration save after waiting for any prior save to complete if (m_configurationSaveComplete.WaitOne()) ThreadPool.QueueUserWorkItem(ExecuteConfigurationSave, state); } finally { Monitor.Exit(m_queuedConfigurationSavePending); } } } private void ExecuteConfigurationSave(object state) { try { // Perform configuration save ConfigurationSaveMode saveMode = (ConfigurationSaveMode)state; m_configuration.Save(saveMode); m_userConfiguration.Save(saveMode == ConfigurationSaveMode.Full); } finally { // Release waiting thread if (m_configurationSaveComplete != null) m_configurationSaveComplete.Set(); } } /// <summary> /// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the specified configuration file. /// </summary> /// <param name="fileName">The path and file name to save the configuration file to.</param> public void SaveAs(string fileName) { m_configuration.SaveAs(fileName); } /// <summary> /// Reloads the current configuration settings from the configuration file that the <see cref="ConfigurationFile"/> represents. /// </summary> public void Reload() { m_configuration = GetConfiguration(m_configuration.FilePath); m_userConfiguration = new UserConfigurationFile(); } /// <summary> /// Restores all the default settings for <see cref="SettingScope.User"/> scoped settings. /// </summary> public void RestoreDefaultUserSettings() { if ((object)m_userConfiguration != null) { string fileName = m_userConfiguration.FileName; if (File.Exists(fileName)) File.Delete(fileName); m_userConfiguration = new UserConfigurationFile(); } } /// <summary> /// Sets the key to be used for encrypting and decrypting values of <see cref="Settings"/>. /// </summary> /// <param name="cryptoKey">New crypto key.</param> public void SetCryptoKey(string cryptoKey) { m_cryptoKey = cryptoKey; } private System.Configuration.Configuration GetConfiguration(string configFilePath) { ApplicationType appType = Common.GetApplicationType(); System.Configuration.Configuration configuration = null; if ((object)configFilePath != null) { if (string.IsNullOrEmpty(configFilePath) || string.Compare(FilePath.GetExtension(configFilePath), ".config", true) == 0) { // PCP - 12/12/2006: Using the TrimEnd function to get the correct value that needs to be passed // to the method call for getting the Configuration object. The previous method (String.TrimEnd()) // yielded incorrect output resulting in the Configuration object not being initialized correctly. switch (appType) { case ApplicationType.WindowsCui: case ApplicationType.WindowsGui: configuration = ConfigurationManager.OpenExeConfiguration(TrimEnd(configFilePath, ".config").EnsureEnd(".exe")); break; case ApplicationType.Web: if (string.IsNullOrEmpty(configFilePath)) configFilePath = HostingEnvironment.ApplicationVirtualPath; configuration = WebConfigurationManager.OpenWebConfiguration(TrimEnd(configFilePath, "web.config")); break; } } else { throw (new ArgumentException("Path of configuration file must be either empty or end in \'.config\'")); } } else { throw (new ArgumentNullException("configFilePath", "Path of configuration file path cannot be null")); } return configuration; } private void CreateConfigurationFile(string configFilePath) { if (!string.IsNullOrEmpty(configFilePath)) {