开发者

Read custom configuration file in C# (Framework 4.0)

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
        }
    }


 // 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


In the past I've used Nini - http://nini.sourceforge.net/manual.php which allows you to read / write custom configuration files (XML / Ini / Registry / .Config) at runtime.

Hope this helps.


My advice with configuration is create your own component to read it.
It may ease the development if at some point you'll decide that you will be getting the configuration from another source like a database or over a web service.
This kind of abstraction also helps you mock the configuration and increases testability (something that the .NET framework doesn't do well at all).
If you are using XML as the configuration format I suggest using Linq to XML.
It's easier to read and use to parse XML files.


You can try Cinchoo framework for your needs. It simplifies development work by code first approach. Define a class as below,

namespace HelloWorld
{
    #region NameSpaces

    using System;
    using Cinchoo.Core.Configuration;

    #endregion NameSpaces

    [ChoConfigurationSection("sample")]
    public class SampleConfigSection : ChoConfigurableObject
    {
        #region Instance Data Members (Public)

        [ChoPropertyInfo("name", DefaultValue="Mark")]
        public string Name;

        [ChoPropertyInfo("message", DefaultValue="Hello World!")]
        public string Message;

        #endregion
    }

    static void Main(string[] args)
    {
        SampleConfigSection sampleConfigSection = new SampleConfigSection();
        Console.WriteLine(sampleConfigSection.ToString());
    }

}

First time, when you run the application it will creates the configuration section in [appexename].xml file as below. Then onward any changes made to this file will be picked up automatically

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="sample" type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, Cinchoo.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7dacd80ff3e33de" />
  </configSections>
  <sample>
    <add key="name" value="Mark" />
    <add key="message" value="Hello World!" />
  </sample>
</configuration>


Or use NameValueCollection easier

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜