History

Renamed folders and separated GSF.Media and GSF.Net into separate projects.

StephenCWills committed 14 years ago

Commit ac1ef661 parent 45bce55628 files · +733 −461Browse files

Showing the changes to Source/Libraries/GSF.Core/Configuration/ConfigurationFile.cs (1 of 628 files). Show all

Unified · Split

Source/Libraries/GSF.Core/Configuration/ConfigurationFile.cs+844−0
@@ -0,0 +1,844 @@
1+//*******************************************************************************************************
2+// ConfigurationFile.cs - Gbtc
3+//
4+// Tennessee Valley Authority, 2009
5+// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
6+//
7+// This software is made freely available under the TVA Open Source Agreement (see below).
8+// Code in this file licensed to GSF under one or more contributor license agreements listed below.
9+//
10+// Code Modification History:
11+// -----------------------------------------------------------------------------------------------------
12+// 04/12/2006 - Pinal C. Patel
13+// Generated original version of source code.
14+// 11/14/2006 - Pinal C. Patel
15+// Modified the ValidateConfigurationFile to save the config file only it was modified.
16+// 12/12/2006 - Pinal C. Patel
17+// Wrote the TrimEnd function that is being used for initialized the Configuration object.
18+// 08/20/2007 - Darrell Zuercher
19+// Edited code comments.
20+// 09/22/2008 - Pinal C. Patel
21+// Converted code to C#.
22+// 09/29/2008 - Pinal C. Patel
23+// Reviewed code comments.
24+// 09/14/2009 - Stephen C. Wills
25+// Added new header and license agreement.
26+// 09/29/2008 - Pinal C. Patel
27+// Added new CurrentWeb and CurrentWin static properties to get the configuration file for a
28+// specific type of application (i.e. Web or Windows).
29+// Modified GetConfiguration() to remove dependency on HttpContext.Current to avoid exception in
30+// async web application operations where HttpContext.Current is null.
31+// 04/20/2010 - Pinal C. Patel
32+// Added static Open() method as the only way of retrieving a ConfigurationFile instance.
33+// Added internal UserConfigurationFile class for accessing and updating user scope settings.
34+// 07/01/2010 - Pinal C. Patel
35+// Removed FileName, AppSettings and ConnectionStrings proxy properties and replaced them with
36+// new Configuration property to allow for full access to the application configuration.
37+// 11/26/2010 - Pinal C. Patel
38+// Updated usage example to include user-scope setting sample.
39+// 12/05/2010 - Pinal C. Patel
40+// Added Culture property that can be used for specifying a culture to use for value conversion.
41+// 01/04/2011 - J. Ritchie Carroll
42+// Modified culture to default to InvariantCulture for English style parsing defaults.
43+// 04/07/2011 - J. Ritchie Carroll
44+// Added a Reload() method to reload the configuration file settings and a
45+// RestoreDefaultUserSettings() method to restore the default user settings.
46+// 12/12/2011 - J. Ritchie Carroll
47+// Added synchronization to save methods such that saves from multiple threads will not
48+// cause issues when lots of new settings are being added.
49+//
50+//*******************************************************************************************************
51+
52+#region [ TVA Open Source Agreement ]
53+/*
54+
55+ THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE,REPRODUCTION, DISTRIBUTION,
56+ MODIFICATION AND REDISTRIBUTION OF CERTAIN COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE
57+ TENNESSEE VALLEY AUTHORITY, A CORPORATE AGENCY AND INSTRUMENTALITY OF THE UNITED STATES GOVERNMENT
58+ ("GOVERNMENT AGENCY"). GOVERNMENT AGENCY IS AN INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT
59+ DISTRIBUTIONS OR REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, DISTRIBUTES,
60+ MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED HEREIN, OR ANY PART THEREOF, IS, BY THAT
61+ ACTION, ACCEPTING IN FULL THE RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT.
62+
63+ Original Software Designation: openPDC
64+ Original Software Title: The GSF Open Source Phasor Data Concentrator
65+ User Registration Requested. Please Visit https://naspi.tva.com/Registration/
66+ Point of Contact for Original Software: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>
67+
68+ 1. DEFINITIONS
69+
70+ A. "Contributor" means Government Agency, as the developer of the Original Software, and any entity
71+ that makes a Modification.
72+
73+ B. "Covered Patents" mean patent claims licensable by a Contributor that are necessarily infringed by
74+ the use or sale of its Modification alone or when combined with the Subject Software.
75+
76+ C. "Display" means the showing of a copy of the Subject Software, either directly or by means of an
77+ image, or any other device.
78+
79+ D. "Distribution" means conveyance or transfer of the Subject Software, regardless of means, to
80+ another.
81+
82+ E. "Larger Work" means computer software that combines Subject Software, or portions thereof, with
83+ software separate from the Subject Software that is not governed by the terms of this Agreement.
84+
85+ F. "Modification" means any alteration of, including addition to or deletion from, the substance or
86+ structure of either the Original Software or Subject Software, and includes derivative works, as that
87+ term is defined in the Copyright Statute, 17 USC § 101. However, the act of including Subject Software
88+ as part of a Larger Work does not in and of itself constitute a Modification.
89+
90+ G. "Original Software" means the computer software first released under this Agreement by Government
91+ Agency entitled openPDC, including source code, object code and accompanying documentation, if any.
92+
93+ H. "Recipient" means anyone who acquires the Subject Software under this Agreement, including all
94+ Contributors.
95+
96+ I. "Redistribution" means Distribution of the Subject Software after a Modification has been made.
97+
98+ J. "Reproduction" means the making of a counterpart, image or copy of the Subject Software.
99+
100+ K. "Sale" means the exchange of the Subject Software for money or equivalent value.
101+
102+ L. "Subject Software" means the Original Software, Modifications, or any respective parts thereof.
103+
104+ M. "Use" means the application or employment of the Subject Software for any purpose.
105+
106+ 2. GRANT OF RIGHTS
107+
108+ A. Under Non-Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor,
109+ with respect to its own contribution to the Subject Software, hereby grants to each Recipient a
110+ non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to
111+ the Subject Software:
112+
113+ 1. Use
114+
115+ 2. Distribution
116+
117+ 3. Reproduction
118+
119+ 4. Modification
120+
121+ 5. Redistribution
122+
123+ 6. Display
124+
125+ B. Under Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with
126+ respect to its own contribution to the Subject Software, hereby grants to each Recipient under Covered
127+ Patents a non-exclusive, world-wide, royalty-free license to engage in the following activities
128+ pertaining to the Subject Software:
129+
130+ 1. Use
131+
132+ 2. Distribution
133+
134+ 3. Reproduction
135+
136+ 4. Sale
137+
138+ 5. Offer for Sale
139+
140+ C. The rights granted under Paragraph B. also apply to the combination of a Contributor's Modification
141+ and the Subject Software if, at the time the Modification is added by the Contributor, the addition of
142+ such Modification causes the combination to be covered by the Covered Patents. It does not apply to
143+ any other combinations that include a Modification.
144+
145+ D. The rights granted in Paragraphs A. and B. allow the Recipient to sublicense those same rights.
146+ Such sublicense must be under the same terms and conditions of this Agreement.
147+
148+ 3. OBLIGATIONS OF RECIPIENT
149+
150+ A. Distribution or Redistribution of the Subject Software must be made under this Agreement except for
151+ additions covered under paragraph 3H.
152+
153+ 1. Whenever a Recipient distributes or redistributes the Subject Software, a copy of this Agreement
154+ must be included with each copy of the Subject Software; and
155+
156+ 2. If Recipient distributes or redistributes the Subject Software in any form other than source code,
157+ Recipient must also make the source code freely available, and must provide with each copy of the
158+ Subject Software information on how to obtain the source code in a reasonable manner on or through a
159+ medium customarily used for software exchange.
160+
161+ B. Each Recipient must ensure that the following copyright notice appears prominently in the Subject
162+ Software:
163+
164+ No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
165+
166+ C. Each Contributor must characterize its alteration of the Subject Software as a Modification and
167+ must identify itself as the originator of its Modification in a manner that reasonably allows
168+ subsequent Recipients to identify the originator of the Modification. In fulfillment of these
169+ requirements, Contributor must include a file (e.g., a change log file) that describes the alterations
170+ made and the date of the alterations, identifies Contributor as originator of the alterations, and
171+ consents to characterization of the alterations as a Modification, for example, by including a
172+ statement that the Modification is derived, directly or indirectly, from Original Software provided by
173+ Government Agency. Once consent is granted, it may not thereafter be revoked.
174+
175+ D. A Contributor may add its own copyright notice to the Subject Software. Once a copyright notice has
176+ been added to the Subject Software, a Recipient may not remove it without the express permission of
177+ the Contributor who added the notice.
178+
179+ E. A Recipient may not make any representation in the Subject Software or in any promotional,
180+ advertising or other material that may be construed as an endorsement by Government Agency or by any
181+ prior Recipient of any product or service provided by Recipient, or that may seek to obtain commercial
182+ advantage by the fact of Government Agency's or a prior Recipient's participation in this Agreement.
183+
184+ F. In an effort to track usage and maintain accurate records of the Subject Software, each Recipient,
185+ upon receipt of the Subject Software, is requested to register with Government Agency by visiting the
186+ following website: https://naspi.tva.com/Registration/. Recipient's name and personal information
187+ shall be used for statistical purposes only. Once a Recipient makes a Modification available, it is
188+ requested that the Recipient inform Government Agency at the web site provided above how to access the
189+ Modification.
190+
191+ G. Each Contributor represents that that its Modification does not violate any existing agreements,
192+ regulations, statutes or rules, and further that Contributor has sufficient rights to grant the rights
193+ conveyed by this Agreement.
194+
195+ H. A Recipient may choose to offer, and to charge a fee for, warranty, support, indemnity and/or
196+ liability obligations to one or more other Recipients of the Subject Software. A Recipient may do so,
197+ however, only on its own behalf and not on behalf of Government Agency or any other Recipient. Such a
198+ Recipient must make it absolutely clear that any such warranty, support, indemnity and/or liability
199+ obligation is offered by that Recipient alone. Further, such Recipient agrees to indemnify Government
200+ Agency and every other Recipient for any liability incurred by them as a result of warranty, support,
201+ indemnity and/or liability offered by such Recipient.
202+
203+ I. A Recipient may create a Larger Work by combining Subject Software with separate software not
204+ governed by the terms of this agreement and distribute the Larger Work as a single product. In such
205+ case, the Recipient must make sure Subject Software, or portions thereof, included in the Larger Work
206+ is subject to this Agreement.
207+
208+ J. Notwithstanding any provisions contained herein, Recipient is hereby put on notice that export of
209+ any goods or technical data from the United States may require some form of export license from the
210+ U.S. Government. Failure to obtain necessary export licenses may result in criminal liability under
211+ U.S. laws. Government Agency neither represents that a license shall not be required nor that, if
212+ required, it shall be issued. Nothing granted herein provides any such export license.
213+
214+ 4. DISCLAIMER OF WARRANTIES AND LIABILITIES; WAIVER AND INDEMNIFICATION
215+
216+ A. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, EITHER
217+ EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT
218+ SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
219+ PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR
220+ FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS
221+ AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR
222+ RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
223+ RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND
224+ LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT
225+ "AS IS."
226+
227+ B. Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST GOVERNMENT AGENCY, ITS
228+ AGENTS, EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE
229+ OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM
230+ SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S USE OF THE
231+ SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS GOVERNMENT AGENCY, ITS AGENTS,
232+ EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY
233+ LAW. THE FOREGOING RELEASE AND INDEMNIFICATION SHALL APPLY EVEN IF THE LIABILITIES, DEMANDS, DAMAGES,
234+ EXPENSES OR LOSSES ARE CAUSED, OCCASIONED, OR CONTRIBUTED TO BY THE NEGLIGENCE, SOLE OR CONCURRENT, OF
235+ GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE
236+ IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
237+
238+ 5. GENERAL TERMS
239+
240+ A. Termination: This Agreement and the rights granted hereunder will terminate automatically if a
241+ Recipient fails to comply with these terms and conditions, and fails to cure such noncompliance within
242+ thirty (30) days of becoming aware of such noncompliance. Upon termination, a Recipient agrees to
243+ immediately cease use and distribution of the Subject Software. All sublicenses to the Subject
244+ Software properly granted by the breaching Recipient shall survive any such termination of this
245+ Agreement.
246+
247+ B. Severability: If any provision of this Agreement is invalid or unenforceable under applicable law,
248+ it shall not affect the validity or enforceability of the remainder of the terms of this Agreement.
249+
250+ C. Applicable Law: This Agreement shall be subject to United States federal law only for all purposes,
251+ including, but not limited to, determining the validity of this Agreement, the meaning of its
252+ provisions and the rights, obligations and remedies of the parties.
253+
254+ D. Entire Understanding: This Agreement constitutes the entire understanding and agreement of the
255+ parties relating to release of the Subject Software and may not be superseded, modified or amended
256+ except by further written agreement duly executed by the parties.
257+
258+ E. Binding Authority: By accepting and using the Subject Software under this Agreement, a Recipient
259+ affirms its authority to bind the Recipient to all terms and conditions of this Agreement and that
260+ Recipient hereby agrees to all terms and conditions herein.
261+
262+ F. Point of Contact: Any Recipient contact with Government Agency is to be directed to the designated
263+ representative as follows: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>.
264+
265+*/
266+#endregion
267+
268+#region [ Contributor License Agreements ]
269+
270+//******************************************************************************************************
271+//
272+// Copyright © 2011, Grid Protection Alliance. All Rights Reserved.
273+//
274+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
275+// not use this file except in compliance with the License. You may obtain a copy of the License at:
276+//
277+// http://www.opensource.org/licenses/eclipse-1.0.php
278+//
279+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
280+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
281+// License for the specific language governing permissions and limitations.
282+//
283+//******************************************************************************************************
284+
285+#endregion
286+
287+using GSF.IO;
288+using GSF.Xml;
289+using System;
290+using System.Collections.Concurrent;
291+using System.Configuration;
292+using System.Globalization;
293+using System.IO;
294+using System.Text;
295+using System.Threading;
296+using System.Web.Configuration;
297+using System.Web.Hosting;
298+using System.Xml;
299+
300+namespace GSF.Configuration
301+{
302+ /// <summary>
303+ /// Represents a configuration file of a Windows or Web application.
304+ /// </summary>
305+ /// <example>
306+ /// This example shows how to save and read settings from the config file:
307+ /// <code>
308+ /// using System;
309+ /// using System.Configuration;
310+ /// using GSF;
311+ /// using GSF.Configuration;
312+ ///
313+ /// class Program
314+ /// {
315+ /// static void Main(string[] args)
316+ /// {
317+ /// // Get the application config file.
318+ /// ConfigurationFile config = ConfigurationFile.Current;
319+ ///
320+ /// // Get the sections of config file.
321+ /// CategorizedSettingsElementCollection startup = config.Settings["Startup"];
322+ /// CategorizedSettingsElementCollection passwords = config.Settings["Passwords"];
323+ /// CategorizedSettingsElementCollection monitoring = config.Settings["Monitoring"];
324+ /// KeyValueConfigurationCollection appSettings = config.Configuration.AppSettings.Settings;
325+ /// ConnectionStringSettingsCollection connStrings = config.Configuration.ConnectionStrings.ConnectionStrings;
326+ ///
327+ /// // Add settings to the config file under the "appSettings" section.
328+ /// appSettings.Add("SaveSettingOnExit", true.ToString());
329+ /// // Add settings to the config file under the "connectionStrings" section.
330+ /// connStrings.Add(new ConnectionStringSettings("DevSql", "Server=SqlServer;Database=Sandbox;Trusted_Connection=True"));
331+ /// // Add settings to the config (if they don't exist) under a custom "monitoring" section.
332+ /// monitoring.Add("RefreshInterval", 5, "Interval in seconds at which the Monitor screen is to be refreshed.");
333+ /// monitoring.Add("MessagesSnapshot", 30000, "Maximum messages length to be displayed on the Monitor screen.");
334+ /// // Add password to the config file encrypted (if it doesn't exist) under a custom "passwords" section.
335+ /// passwords.Add("Admin", "Adm1nP4ss", "Password used for performing administrative tasks.", true);
336+ /// // Add user-scope setting to the config (if it doesn't exist) under a custom "startup" section.
337+ /// startup.Add("Theme", "Default", "Application theme to use for the session.", false, SettingScope.User);
338+ /// config.Save(); // Save settings to the config file.
339+ ///
340+ /// // Read saved settings from the config file.
341+ /// bool saveSettingsOnExit = appSettings["SaveSettingOnExit"].Value.ParseBoolean();
342+ /// string devConnectionString = connStrings["DevSql"].ConnectionString;
343+ /// string appTheme = startup["Theme"].Value;
344+ /// string adminPassword = passwords["Admin"].Value;
345+ /// int refreshInterval = monitoring["RefreshInterval"].ValueAsInt32();
346+ /// int messagesSnapshot = monitoring["MessagesSnapshot"].ValueAsInt32();
347+ ///
348+ /// // Print the retrieved settings to the console.
349+ /// Console.WriteLine("SaveSettingOnExit = {0}", saveSettingsOnExit);
350+ /// Console.WriteLine("DevSql = {0}", devConnectionString);
351+ /// Console.WriteLine("Theme = {0}", appTheme);
352+ /// Console.WriteLine("Admin = {0}", adminPassword);
353+ /// Console.WriteLine("RefreshInterval = {0}", refreshInterval);
354+ /// Console.WriteLine("MessagesSnapshot = {0}", messagesSnapshot);
355+ ///
356+ /// Console.ReadLine();
357+ /// }
358+ /// }
359+ /// </code>
360+ /// This example shows the content of the config file from the sample code above:
361+ /// <code>
362+ /// <![CDATA[
363+ /// <?xml version="1.0" encoding="utf-8"?>
364+ /// <configuration>
365+ /// <configSections>
366+ /// <section name="categorizedSettings" type="GSF.Configuration.CategorizedSettingsSection, GSF.Core" />
367+ /// </configSections>
368+ /// <appSettings>
369+ /// <add key="SaveSettingOnExit" value="True" />
370+ /// </appSettings>
371+ /// <categorizedSettings>
372+ /// <startup>
373+ /// <add name="Theme" value="Default" description="Application theme to use for the session."
374+ /// encrypted="false" scope="User" />
375+ /// </startup>
376+ /// <passwords>
377+ /// <add name="Admin" value="C+0j6fE/N0Q9b5xaeDKgvRmSeY9zJkO1EQCr7cHoG3x24tztlbBB54PfWsuMGXc/"
378+ /// description="Password used for performing administrative tasks."
379+ /// encrypted="true" />
380+ /// </passwords>
381+ /// <monitoring>
382+ /// <add name="RefreshInterval" value="5" description="Interval in seconds at which the Monitor screen is to be refreshed."
383+ /// encrypted="false" />
384+ /// <add name="MessagesSnapshot" value="30000" description="Maximum messages length to be displayed on the Monitor screen."
385+ /// encrypted="false" />
386+ /// </monitoring>
387+ /// </categorizedSettings>
388+ /// <connectionStrings>
389+ /// <add name="DevSql" connectionString="Server=SqlServer;Database=Sandbox;Trusted_Connection=True" />
390+ /// </connectionStrings>
391+ /// </configuration>
392+ /// ]]>
393+ /// </code>
394+ /// </example>
395+ /// <seealso cref="CategorizedSettingsSection"/>
396+ /// <seealso cref="CategorizedSettingsElement"/>
397+ /// <seealso cref="CategorizedSettingsElementCollection"/>
398+ // Since each instance of this class is statically cached for the process lifetime, IDisposable is not implemented so that
399+ // the instance will not be inadvertently disposed
400+ public class ConfigurationFile
401+ {
402+ #region [ Members ]
403+
404+ // Nested Types
405+
406+ internal class UserConfigurationFile
407+ {
408+ private string m_fileName;
409+ private XmlDocument m_settings;
410+ private bool m_settingsModified;
411+
412+ private const string RootNode = "settings";
413+ private const string Filename = "Settings.xml";
414+
415+ public UserConfigurationFile()
416+ {
417+ m_settings = new XmlDocument();
418+ m_fileName = Path.Combine(FilePath.GetApplicationDataFolder(), Filename);
419+ if (File.Exists(m_fileName))
420+ {
421+ // Load existing settings.
422+ m_settings.Load(m_fileName);
423+ }
424+ else
425+ {
426+ // Create new settings file.
427+ m_settings.AppendChild(m_settings.CreateNode(XmlNodeType.XmlDeclaration, null, null));
428+ m_settings.AppendChild(m_settings.CreateElement(RootNode));
429+ }
430+ }
431+
432+ public string FileName
433+ {
434+ get
435+ {
436+ return m_fileName;
437+ }
438+ }
439+
440+ public void Save(bool force)
441+ {
442+ if (force || m_settingsModified)
443+ {
444+ // Create directory if missing.
445+ string folder = FilePath.GetDirectoryName(m_fileName);
446+ if (!Directory.Exists(folder))
447+ Directory.CreateDirectory(folder);
448+
449+ // Save settings to the file.
450+ m_settings.Save(m_fileName);
451+ }
452+ }
453+
454+ public void Write(string category, string name, string value)
455+ {
456+ XmlNode node = GetSetting(category, name);
457+ if ((object)node != null)
458+ {
459+ // Setting exists so update it.
460+ node.SetAttributeValue("value", value);
461+ }
462+ else
463+ {
464+ // Setting doesn't exist so add it.
465+ XmlNode setting = m_settings.CreateElement("add");
466+ setting.SetAttributeValue("name", name);
467+ setting.SetAttributeValue("value", value);
468+ m_settings.GetXmlNode(category).AppendChild(setting);
469+ }
470+ m_settingsModified = true;
471+ }
472+
473+ public string Read(string category, string name, string defaultValue)
474+ {
475+ XmlNode node = GetSetting(category, name);
476+ if ((object)node != null)
477+ // Setting exists so return its value.
478+ return node.Attributes["value"].Value;
479+ else
480+ // Setting doesn't exist so return the default.
481+ return defaultValue;
482+ }
483+
484+ public XmlNode GetSetting(string category, string name)
485+ {
486+ return m_settings.SelectSingleNode(string.Format("{0}/{1}/add[@name='{2}']", RootNode, category, name));
487+ }
488+ }
489+
490+ // Constants
491+ private const string CustomSectionName = "categorizedSettings";
492+ private const string CustomSectionType = "TVA.Configuration.CategorizedSettingsSection, TVA.Core";
493+
494+ // Fields
495+ private string m_cryptoKey;
496+ private CultureInfo m_culture;
497+ private System.Configuration.Configuration m_configuration;
498+ private UserConfigurationFile m_userConfiguration;
499+ private object m_queuedConfigurationSavePending;
500+ private AutoResetEvent m_configurationSaveComplete;
501+
502+ #endregion
503+
504+ #region [ Constructors ]
505+
506+ /// <summary>
507+ /// Initializes a new instance of the <see cref="ConfigurationFile"/> class.
508+ /// </summary>
509+ internal ConfigurationFile(string configFilePath)
510+ {
511+ m_culture = CultureInfo.InvariantCulture;
512+ m_queuedConfigurationSavePending = new object();
513+ m_configurationSaveComplete = new AutoResetEvent(true);
514+
515+ m_configuration = GetConfiguration(configFilePath);
516+
517+ if (m_configuration.HasFile)
518+ ValidateConfigurationFile(m_configuration.FilePath);
519+ else
520+ CreateConfigurationFile(m_configuration.FilePath);
521+
522+ m_configuration = GetConfiguration(configFilePath);
523+ m_userConfiguration = new UserConfigurationFile();
524+ }
525+
526+ #endregion
527+
528+ #region [ Properties ]
529+
530+ /// <summary>
531+ /// Gets or sets the <see cref="CultureInfo"/> to use for the conversion of setting values to and from <see cref="string"/>.
532+ /// </summary>
533+ public CultureInfo Culture
534+ {
535+ get
536+ {
537+ return m_culture;
538+ }
539+ set
540+ {
541+ if ((object)value != null)
542+ m_culture = value;
543+ else
544+ m_culture = CultureInfo.InvariantCulture;
545+ }
546+ }
547+
548+ /// <summary>
549+ /// Get the underlying <see cref="System.Configuration.Configuration"/> that can be accessed using this <see cref="ConfigurationFile"/> object.
550+ /// </summary>
551+ public System.Configuration.Configuration Configuration
552+ {
553+ get
554+ {
555+ return m_configuration;
556+ }
557+ }
558+
559+ /// <summary>
560+ /// Gets the <see cref="CategorizedSettingsSection"/> object representing settings under the "categorizedSettings" section of the config file.
561+ /// </summary>
562+ public CategorizedSettingsSection Settings
563+ {
564+ get
565+ {
566+ CategorizedSettingsSection settings = (CategorizedSettingsSection)m_configuration.GetSection(CustomSectionName);
567+ settings.File = this;
568+ settings.SetCryptoKey(m_cryptoKey);
569+ return settings;
570+ }
571+ }
572+
573+ /// <summary>
574+ /// Gets the <see cref="UserConfigurationFile"/> where user specific settings are saved.
575+ /// </summary>
576+ internal UserConfigurationFile UserSettings
577+ {
578+ get
579+ {
580+ return m_userConfiguration;
581+ }
582+ }
583+
584+ #endregion
585+
586+ #region [ Methods ]
587+
588+ /// <summary>
589+ /// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the configuration file that it represents.
590+ /// </summary>
591+ public void Save()
592+ {
593+ Save(ConfigurationSaveMode.Modified);
594+ }
595+
596+ /// <summary>
597+ /// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the configuration file that it represents.
598+ /// </summary>
599+ /// <param name="saveMode">One of the <see cref="ConfigurationSaveMode"/> values.</param>
600+ public void Save(ConfigurationSaveMode saveMode)
601+ {
602+ // Since the static open method always returns the same instance for the same configuration files,
603+ // synchronizing the instance will sync all saves.
604+ ThreadPool.QueueUserWorkItem(QueueConfigurationSave, saveMode);
605+ }
606+
607+ private void QueueConfigurationSave(object state)
608+ {
609+ // Queue up a configuration save unless another thread has already requested one
610+ if (Monitor.TryEnter(m_queuedConfigurationSavePending))
611+ {
612+ try
613+ {
614+ // Queue new configuration save after waiting for any prior save to complete
615+ if (m_configurationSaveComplete.WaitOne())
616+ ThreadPool.QueueUserWorkItem(ExecuteConfigurationSave, state);
617+ }
618+ finally
619+ {
620+ Monitor.Exit(m_queuedConfigurationSavePending);
621+ }
622+ }
623+ }
624+
625+ private void ExecuteConfigurationSave(object state)
626+ {
627+ try
628+ {
629+ // Perform configuration save
630+ ConfigurationSaveMode saveMode = (ConfigurationSaveMode)state;
631+ m_configuration.Save(saveMode);
632+ m_userConfiguration.Save(saveMode == ConfigurationSaveMode.Full);
633+ }
634+ finally
635+ {
636+ // Release waiting thread
637+ if (m_configurationSaveComplete != null)
638+ m_configurationSaveComplete.Set();
639+ }
640+ }
641+
642+ /// <summary>
643+ /// Writes the configuration settings contained within this <see cref="ConfigurationFile"/> object to the specified configuration file.
644+ /// </summary>
645+ /// <param name="fileName">The path and file name to save the configuration file to.</param>
646+ public void SaveAs(string fileName)
647+ {
648+ m_configuration.SaveAs(fileName);
649+ }
650+
651+ /// <summary>
652+ /// Reloads the current configuration settings from the configuration file that the <see cref="ConfigurationFile"/> represents.
653+ /// </summary>
654+ public void Reload()
655+ {
656+ m_configuration = GetConfiguration(m_configuration.FilePath);
657+ m_userConfiguration = new UserConfigurationFile();
658+ }
659+
660+ /// <summary>
661+ /// Restores all the default settings for <see cref="SettingScope.User"/> scoped settings.
662+ /// </summary>
663+ public void RestoreDefaultUserSettings()
664+ {
665+ if ((object)m_userConfiguration != null)
666+ {
667+ string fileName = m_userConfiguration.FileName;
668+
669+ if (File.Exists(fileName))
670+ File.Delete(fileName);
671+
672+ m_userConfiguration = new UserConfigurationFile();
673+ }
674+ }
675+
676+ /// <summary>
677+ /// Sets the key to be used for encrypting and decrypting values of <see cref="Settings"/>.
678+ /// </summary>
679+ /// <param name="cryptoKey">New crypto key.</param>
680+ public void SetCryptoKey(string cryptoKey)
681+ {
682+ m_cryptoKey = cryptoKey;
683+ }
684+
685+ private System.Configuration.Configuration GetConfiguration(string configFilePath)
686+ {
687+ ApplicationType appType = Common.GetApplicationType();
688+ System.Configuration.Configuration configuration = null;
689+
690+ if ((object)configFilePath != null)
691+ {
692+ if (string.IsNullOrEmpty(configFilePath) || string.Compare(FilePath.GetExtension(configFilePath), ".config", true) == 0)
693+ {
694+ // PCP - 12/12/2006: Using the TrimEnd function to get the correct value that needs to be passed
695+ // to the method call for getting the Configuration object. The previous method (String.TrimEnd())
696+ // yielded incorrect output resulting in the Configuration object not being initialized correctly.
697+ switch (appType)
698+ {
699+ case ApplicationType.WindowsCui:
700+ case ApplicationType.WindowsGui:
701+ configuration = ConfigurationManager.OpenExeConfiguration(TrimEnd(configFilePath, ".config").EnsureEnd(".exe"));
702+ break;
703+ case ApplicationType.Web:
704+ if (string.IsNullOrEmpty(configFilePath))
705+ configFilePath = HostingEnvironment.ApplicationVirtualPath;
706+ configuration = WebConfigurationManager.OpenWebConfiguration(TrimEnd(configFilePath, "web.config"));
707+ break;
708+ }
709+ }
710+ else
711+ {
712+ throw (new ArgumentException("Path of configuration file must be either empty or end in \'.config\'"));
713+ }
714+ }
715+ else
716+ {
717+ throw (new ArgumentNullException("configFilePath", "Path of configuration file path cannot be null"));
718+ }
719+
720+ return configuration;
721+ }
722+
723+ private void CreateConfigurationFile(string configFilePath)
724+ {
725+ if (!string.IsNullOrEmpty(configFilePath))
726+ {
727+ XmlTextWriter configFileWriter = new XmlTextWriter(configFilePath, Encoding.UTF8);
728+ configFileWriter.Indentation = 4;
729+ configFileWriter.Formatting = Formatting.Indented;
730+ // Populates the very basic information required in a config file.
731+ configFileWriter.WriteStartDocument();
732+ configFileWriter.WriteStartElement("configuration");
733+ configFileWriter.WriteEndElement();
734+ configFileWriter.WriteEndDocument();
735+ // Closes the config file.
736+ configFileWriter.Close();
737+
738+ ValidateConfigurationFile(configFilePath);
739+ }
740+ else
741+ {
742+ throw (new ArgumentNullException("configFilePath", "Path of configuration file path cannot be null"));
743+ }
744+ }
745+
746+ // Validate configuration file
747+ private void ValidateConfigurationFile(string configFilePath)
748+ {
749+ if (!string.IsNullOrEmpty(configFilePath))
750+ {
751+ XmlDocument configFile = new XmlDocument();
752+ bool configFileModified = false;
753+ configFile.Load(configFilePath);
754+
755+ // Make sure that the config file has the necessary section information under <customSections />
756+ // that is required by the .Net configuration API to process our custom <categorizedSettings />
757+ // section. The configuration API will raise an exception if it doesn't find this section.
758+ if (configFile.DocumentElement.SelectNodes("configSections").Count == 0)
759+ {
760+ // Adds a <configSections> node, if one is not present.
761+ configFile.DocumentElement.InsertBefore(configFile.CreateElement("configSections"), configFile.DocumentElement.FirstChild);
762+
763+ configFileModified = true;
764+ }
765+ XmlNode configSectionsNode = configFile.DocumentElement.SelectSingleNode("configSections");
766+ if (configSectionsNode.SelectNodes("section[@name = \'" + CustomSectionName + "\']").Count == 0)
767+ {
768+ // Adds the <section> node that specifies the DLL that handles the <categorizedSettings> node in
769+ // the config file, if one is not present.
770+ XmlNode node = configFile.CreateElement("section");
771+ node.SetAttributeValue("name", CustomSectionName);
772+ node.SetAttributeValue("type", CustomSectionType);
773+ configSectionsNode.AppendChild(node);
774+
775+ configFileModified = true;
776+ }
777+
778+ // 11/14/2006 - PCP: We'll save the config file only it was modified. This will prevent ASP.Net
779+ // web sites from restarting every time a configuration element is accessed.
780+ if (configFileModified)
781+ {
782+ configFile.Save(configFilePath);
783+ }
784+ }
785+ else
786+ {
787+ throw (new ArgumentNullException("configFilePath", "Path of configuration file path cannot be null"));
788+ }
789+ }
790+
791+ // Trim suffix from end of string
792+ private string TrimEnd(string stringToTrim, string textToTrim)
793+ {
794+ int trimEndIndex = stringToTrim.LastIndexOf(textToTrim, StringComparison.CurrentCultureIgnoreCase);
795+
796+ if (trimEndIndex == -1)
797+ trimEndIndex = stringToTrim.Length;
798+
799+ return stringToTrim.Substring(0, trimEndIndex);
800+ }
801+
802+ #endregion
803+
804+ #region [ Static ]
805+
806+ // Static Fields
807+ private static ConcurrentDictionary<string, ConfigurationFile> s_configFiles;
808+
809+ // Static Constructor
810+
811+ static ConfigurationFile()
812+ {
813+ s_configFiles = new ConcurrentDictionary<string, ConfigurationFile>(StringComparer.CurrentCultureIgnoreCase);
814+ }
815+
816+ // Static Properties
817+
818+ /// <summary>
819+ /// Gets the <see cref="ConfigurationFile"/> object that represents the config file of the currently executing Windows or Web application.
820+ /// </summary>
821+ public static ConfigurationFile Current
822+ {
823+ get
824+ {
825+ return Open(string.Empty);
826+ }
827+ }
828+
829+ // Static Methods
830+
831+ /// <summary>
832+ /// Opens application config file at the specified <paramref name="configFilePath"/>.
833+ /// </summary>
834+ /// <param name="configFilePath">Path of the config file that belongs to a Windows or Web application.</param>
835+ /// <returns>An <see cref="ConfigurationFile"/> object.</returns>
836+ public static ConfigurationFile Open(string configFilePath)
837+ {
838+ // Retrieve config file from cache if present or else add it for subsequent uses.
839+ return s_configFiles.GetOrAdd(configFilePath, path => new ConfigurationFile(path));
840+ }
841+
842+ #endregion
843+ }
844+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t