Read custom configuration file in C# (Framework 4.0)

Koby Mizrahy picture Koby Mizrahy · Jun 14, 2011 · Viewed 65.8k times · Source

I am developing an application in C# under Framework 4.0.

In my application I would like to create separate configuration file that is not the app.config file. The configuration file contains custom configuration sections we developed for the product.

I don't want to reference this file from the app.config using the configSource.

I want to load it at runtime and read it's content.

An example to what I mean is the log4net that allow you to write the configuration in the log4net.config file.

Can anyone help how to do that without writing code that mimcs the code that exists in the framework ?

UPDATE:

based on the answer from Kaido I wrote utility class that reads custom configuration file and has the ability to refresh the Config content when the file on the file system changes.

The usage in this class is as follows:

  1. Get the configuration file content

    // Create configuration reader that reads the files once
    var configFileReader = new CustomConfigurationFileReader("c:\\myconfig.config");
    var config = configFileReader.Config;
    
    // Do any action you want with the config object like:
    config.GetSection("my.custom.section");
    
    // or,
    var someVal = config.AppSettings.Settings["someKey"];
    
  2. Get notifications when the configuration file changes

    // Create configuration reader that notifies when the configuraiton file changes
    var configFileReader = new CustomConfigurationFileReader("c:\\myconfig.config", true);
    
    // Register to the FileChanged event
    configFileReader.FileChanged += MyEventHandler;
    
    ...
    
    private void MyEventHanler(object sender, EventArgs e)
    {
         // You can safely access the Config property here, it is already contains the new content
    }
    

In the code I used PostSharp in order to validate the constructor input parameter to verify that the log file is not null and that the file exists. You can change the code to make those validation inline in the code (although I recomend to use PostSharp to seperate the application to aspects).

Here is the code:

    using System;
    using System.Configuration;
    using System.IO;
    using CSG.Core.Validation;

    namespace CSG.Core.Configuration
    {
        /// <summary>
        /// Reads customer configuration file
        /// </summary>
        public class CustomConfigurationFileReader
        {
            // By default, don't notify on file change
            private const bool DEFAULT_NOTIFY_BEHAVIOUR = false;

            #region Fields

            // The configuration file name
            private readonly string _configFileName;

            /// <summary>
            /// Raises when the configuraiton file is modified
            /// </summary>
            public event System.EventHandler FileChanged;

            #endregion Fields

            #region Constructor

            /// <summary>
            /// Initialize a new instance of the CustomConfigurationFileReader class that notifies 
            /// when the configuration file changes.
            /// </summary>
            /// <param name="configFileName">The full path to the custom configuration file</param>
            public CustomConfigurationFileReader(string configFileName)
                : this(configFileName, DEFAULT_NOTIFY_BEHAVIOUR)
            {            
            }        

            /// <summary>
            /// Initialize a new instance of the CustomConfigurationFileReader class
            /// </summary>
            /// <param name="configFileName">The full path to the custom configuration file</param>
            /// <param name="notifyOnFileChange">Indicate if to raise the FileChange event when the configuraiton file changes</param>
            [ValidateParameters]
            public CustomConfigurationFileReader([NotNull, FileExists]string configFileName, bool notifyOnFileChange)
            {
                // Set the configuration file name
                _configFileName = configFileName;

                // Read the configuration File
                ReadConfiguration();

                // Start watch the configuration file (if notifyOnFileChanged is true)
                if(notifyOnFileChange)
                    WatchConfigFile();
            }

            #endregion Constructor        

            /// <summary>
            /// Get the configuration that represents the content of the configuration file
            /// </summary>
            public System.Configuration.Configuration Config
            {
                get;
                set;
            }

            #region Helper Methods

            /// <summary>
            /// Watch the configuraiton file for changes
            /// </summary>
            private void WatchConfigFile()
            {
                var watcher = new FileSystemWatcher(_configFileName);
                watcher.Changed += ConfigFileChangedEvent;
            }

            /// <summary>
            /// Read the configuration file
            /// </summary>
            public void ReadConfiguration()
            {
                // Create config file map to point to the configuration file
                var configFileMap = new ExeConfigurationFileMap
                {
                    ExeConfigFilename = _configFileName
                };

                // Create configuration object that contains the content of the custom configuration file
                Config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
            }        

            /// <summary>
            /// Called when the configuration file changed.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void ConfigFileChangedEvent(object sender, FileSystemEventArgs e)
            {
                // Check if the file changed event has listeners
                if (FileChanged != null)
                    // Raise the event
                    FileChanged(this, new EventArgs());
            }

            #endregion Helper Methods
        }
    }

Answer

Kaido picture Kaido · Jun 14, 2011
 // Map the roaming configuration file. This
      // enables the application to access 
      // the configuration file using the
      // System.Configuration.Configuration class
      ExeConfigurationFileMap configFileMap =
        new ExeConfigurationFileMap();
      configFileMap.ExeConfigFilename = 
        roamingConfig.FilePath;

      // Get the mapped configuration file.
      Configuration config =
        ConfigurationManager.OpenMappedExeConfiguration(
          configFileMap, ConfigurationUserLevel.None);

from http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.aspx