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
287using GSF.IO;
288using GSF.Xml;
289using System;
290using System.Collections.Concurrent;
291using System.Configuration;
292using System.Globalization;
293using System.IO;
294using System.Text;
295using System.Threading;
296using System.Web.Configuration;
297using System.Web.Hosting;
298using System.Xml;
299
300namespace 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