读取 C# 中的自定义配置文件(Framework 4.0)
我正在 Framework 4.0 下用 C# 开发一个应用程序。
在我的应用程序中,我想创建单独的配置文件,而不是 app.config 文件。配置文件包含我们为产品开发的自定义配置部分。
我不想使用 configSource 从 app.config 引用此文件。
我想在运行时加载它并读取它的内容。
我的意思的一个例子是 log4net,它允许您在 log4net.config 文件中写入配置。
任何人都可以帮助如何在不编写模拟框架中存在的代码的代码的情况下做到这一点吗?
更新:
基于Kaido的答案,我编写了实用程序类,该实用程序类读取自定义配置文件,并能够在文件系统上的文件发生更改时刷新配置内容。
该类中的用法如下:
获取配置文件内容
// 创建读取文件一次的配置读取器 var configFileReader = new CustomConfigurationFileReader("c:\\myconfig.config"); var config = configFileReader.Config; // 对配置对象执行任何您想要的操作,例如: config.GetSection("my.custom.section"); // 或者, var someVal = config.AppSettings.Settings["someKey"];
配置文件更改时获取通知
// 创建配置读取器,当配置文件更改时发出通知 var configFileReader = new CustomConfigurationFileReader("c:\\myconfig.config", true); // 注册FileChanged事件 configFileReader.FileChanged += MyEventHandler; ... 私人无效MyEventHanler(对象发送者,EventArgs e) { // 您可以在这里安全地访问 Config 属性,它已经包含新内容 }
在代码中,我使用 PostSharp 来验证构造函数输入参数,以验证日志文件不为空并且该文件存在。您可以更改代码以使这些验证内联在代码中(尽管我建议使用 PostSharp 将应用程序分为各个方面)。
这是代码:
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
}
}
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:
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"];
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
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
来自 http://msdn.microsoft.com/en-us/库/system.configuration.configurationmanager.aspx
from http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.aspx
过去我使用过 Nini - http://nini.sourceforge.net/manual.php 它允许您在运行时读取/写入自定义配置文件(XML/Ini/Registry/.Config)。
希望这有帮助。
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.
我对配置的建议是创建您自己的组件来读取它。
如果在某个时候您决定从数据库或 Web 服务等其他来源获取配置,这可能会简化开发过程。
这种抽象还可以帮助您模拟配置并提高可测试性(.NET 框架根本无法做到这一点)。
如果您使用 XML 作为配置格式,我建议使用 Linq to XML。
它更容易阅读和用于解析 XML 文件。
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.
您可以根据您的需求尝试 Cinchoo 框架。它通过代码优先方法简化了开发工作。定义一个类如下,
第一次,当您运行应用程序时,它将在 [appexename].xml 文件中创建配置部分,如下所示。然后,对此文件所做的任何更改都会自动生效
You can try Cinchoo framework for your needs. It simplifies development work by code first approach. Define a class as below,
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
或者更轻松地使用 NameValueCollection
Or use NameValueCollection easier