简体   繁体   English

读取 C# 中的自定义配置文件(框架 4.0)

[英]Read custom configuration file in C# (Framework 4.0)

I am developing an application in C# under Framework 4.0.我正在框架 4.0 下的 C# 中开发应用程序。

In my application I would like to create separate configuration file that is not the app.config file.在我的应用程序中,我想创建不是 app.config 文件的单独配置文件。 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.我不想使用 configSource 从 app.config 引用此文件。

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.我的意思的一个例子是 log4net,它允许您在 log4net.config 文件中写入配置。

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.根据Kaido的回答,我编写了实用程序 class 读取自定义配置文件并能够在文件系统上的文件更改时刷新配置内容。

The usage in this class is as follows:这个class中的用法如下:

  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.在代码中,我使用 PostSharp 来验证构造函数输入参数,以验证日志文件不是 null 并且该文件存在。 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).您可以更改代码以使这些验证内联在代码中(尽管我建议使用 PostSharp 将应用程序分离到各个方面)。

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来自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.过去我使用过 Nini - http://nini.sourceforge.net/manual.php ,它允许您在运行时读取/写入自定义配置文件(XML / Ini / Registry /.Config)。

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.如果在某个时候您决定从另一个来源(如数据库)或通过 web 服务获取配置,这可能会简化开发。
This kind of abstraction also helps you mock the configuration and increases testability (something that the .NET framework doesn't do well at all).这种抽象还可以帮助您模拟配置并提高可测试性(.NET 框架根本没有做好这一点)。
If you are using XML as the configuration format I suggest using Linq to XML.如果您使用 XML 作为配置格式,我建议使用 Linq 到 XML。
It's easier to read and use to parse XML files.它更易于阅读和使用来解析 XML 文件。

You can try Cinchoo framework for your needs.您可以根据需要尝试Cinchoo 框架 It simplifies development work by code first approach.它通过代码优先的方法简化了开发工作。 Define a class as below,定义一个 class 如下,

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.第一次,当您运行应用程序时,它将在 [appexename].xml 文件中创建配置部分,如下所示。 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或者更容易使用NameValueCollection

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM