自定义配置文件

可以在Visual Studio中添加自定义的配置文件,并使用ConfigurationManager.OpenMappedExeConfiguration打开该配置文件进行读写操作。

ExeConfigurationFileMap configFileMap =new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = @"Configuration\Michael.Config";
var configFile = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
if (settings["Setting1"] == null)
{
    settings.Add("Setting1", "Hello World3");
}
else
{
    settings["Setting1"].Value = "Hello World4";
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<appSettings>
		<add key="Setting1" value="Hello World2" />
		<add key="Setting2" value="May 6, 2014" />
	</appSettings>
</configuration>

日志文件夹

ConfigurationAllowExeDefinition

In .NET Configuration hierarchy, there’re four configuration levels for windows applications:
LocalUser.config –> RoamingUser.config –> Application.config (appname.exe.config) –> Machine.config

A configuration section, for example: appSettings, always has an allowExeDefinition attribute associated, The valid values for this setting are:

  • MachineOnly = the ConfigurationSection can be defined only in the Machine.config file.
  • MachineToApplication = the ConfigurationSection can be defined either in the Machine.config file or in the Exe.config file in the client application directory. This is the default value.
  • MachineToLocalUser = the ConfigurationSection can be defined in the Machine.config, in the Exe.config file in the client application directory, in the User.config file in the roaming user directory, or in the User.config file in the local user directory.
  • MachineToRoamingUser = the ConfigurationSection can be defined in the Machine.config file, in the Exe.config file in the client application directory, or in the User.config file in the roaming user directory.

In machine.config, appSettings section is defined with allowExeDefinition=”MachineToApplication”, so we cannot write this section user’s config, either roaming or local.

config在AppData/Local中的存储文件夹

如果项目属性设置了公司,则会在AppData/Local创建一个文件夹,然后在创建程序文件夹,而不是在AppData/Local中直接创建程序文件夹。
日志文件夹
日志文件夹

ConfigurationUserLevel

ConfigurationUserLevel控制配置文件读取的位置,打开后,FilePath的值分别为运行程序目录,AppData\Roaming目录和AppData\Local目录:

//Configuration.FilePath=C:\Users\CNMIZHU7\Source\repos\ConsoleAppTest\ConsoleAppTest\bin\Debug\ConsoleAppTest.exe.Config
var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

//Configuration.FilePath=C:\Users\CNMIZHU7\AppData\Roaming\ConsoleAppTest\ConsoleAppTest.exe_Url_elbjcbdve0qxmi3nkuse25f1orh0myph\1.0.0.0\user.config
var configFileRoaming = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);

//Configuration.FilePath=C:\Users\CNMIZHU7\AppData\Local\ConsoleAppTest\ConsoleAppTest.exe_Url_elbjcbdve0qxmi3nkuse25f1orh0myph\1.0.0.0\user.config
var configFileLocal = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);

allowExeDefinition & ConfigurationUserLeve(ConfigurationManager.OpenExeConfiguration)

  1. allowExeDefinition=MachineOnly (只能在 Machine.config 文件中定义)
    • ConfigurationUserLevel=None, 不可读,不可写
    • ConfigurationUserLevel=PerUserRoaming, 不可读,不可写
    • ConfigurationUserLevel=PerUserRoamingAndLocal,不可读,不可写
  2. allowExeDefinition=MachineToApplication (可在 Machine.config 或Exe.config)
    • ConfigurationUserLevel=None, 可读写,存储在程序目录
    • ConfigurationUserLevel=PerUserRoaming, 可读,和ConfigurationUserLevel=None数据一致,不可写
    • ConfigurationUserLevel=PerUserRoamingAndLocal,不可读,不可写
  3. allowExeDefinition=MachineToRoamingUser (可在 Machine.config 或Exe.config 或AppData\Roaming\User.config)
    • ConfigurationUserLevel=None, 可读写,存储在程序目录
    • ConfigurationUserLevel=PerUserRoaming, 可读写,存储在AppData\Roaming目录
    • ConfigurationUserLevel=PerUserRoamingAndLocal,不可读,不可写
  4. allowExeDefinition=MachineToLocalUser (可在 Machine.config 或Exe.config 或AppData\Roaming\User.config或AppData\Local\User.config)
    • ConfigurationUserLevel=None, 可读写,存储在程序目录
    • ConfigurationUserLevel=PerUserRoaming, 可读写,存储在AppData\Roaming目录
    • ConfigurationUserLevel=PerUserRoamingAndLocal,可读写,存储在AppData\Local目录

AppSettingsSection

allowExeDefinition=MachineToApplication, 不可修改。所以如果需要修改AppSettings的配置,只能通过ConfigurationUserLevel=None打开文件。

Configuration.Save

如果需要保存不同级别的(MachineToApplication,MachineToLocalUser)的配置,需要一个接一个的打开和保存,不能同时打开两个,然后一起修改后,统一保存。只能在保存一个配置后,再打开另一个配置文件。如果使用自定义位置的配置文件,需要先设置自定义配置文件的对应位置。分别为ExeConfigFilename,LocalUserConfigFilename,RoamingUserConfigFilename。

ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = @"Configuration\Michael.Config";
configFileMap.LocalUserConfigFilename = @"Configuration\MichaelLocal.Config";
configFileMap.RoamingUserConfigFilename = @"Configuration\MichaelRoaming.Config";

//var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var configFile = ConfigurationManager.OpenMappedExeConfiguration(configFileMap,ConfigurationUserLevel.None);
CustomSection customSection = configFile.GetSection("CustomSection") as CustomSection;
customSection.MaxUsers = 11;    
configFile.Save(ConfigurationSaveMode.Modified);

//var configFileRoaming = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
var configFileRoaming = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.PerUserRoaming);
CustomSection customSectionRoaming = configFileRoaming.GetSection("CustomSection") as CustomSection;
customSectionRoaming.MaxUsers = 22;   
configFileRoaming.Save(ConfigurationSaveMode.Modified);

//var configFileLocal = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
var configFileLocal = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.PerUserRoamingAndLocal);
CustomSection customSectionLocal = configFileLocal.GetSection("CustomSection") as CustomSection;
customSectionLocal.MaxUsers = 33;
configFileLocal.Save(ConfigurationSaveMode.Modified);

CustomSection

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<section name="CustomSection" type="ConsoleAppTest.Configuration.CustomSection, ConsoleAppTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowExeDefinition="MachineToLocalUser"  requirePermission="false" />
	</configSections>
	<CustomSection fileName="default.txt" maxUsers="1996" maxIdleTime="00:15:00" />
	<appSettings>
		<add key="Setting1" value="Hello World2" />
		<add key="Setting2" value="May 6, 2014" />
	</appSettings>
</configuration>

public sealed class CustomSection :
    ConfigurationSection
{
    // The collection (property bag) that contains 
    // the section properties.
    private static ConfigurationPropertyCollection _Properties;

    // Internal flag to disable 
    // property setting.
    private static bool _ReadOnly;

    // The FileName property.
    private static readonly ConfigurationProperty _FileName =
        new ConfigurationProperty("fileName",
        typeof(string), "default.txt",
        ConfigurationPropertyOptions.IsRequired);

    // The MaxUsers property.
    private static readonly ConfigurationProperty _MaxUsers =
        new ConfigurationProperty("maxUsers",
        typeof(long), (long)1000,
        ConfigurationPropertyOptions.None);

    // The MaxIdleTime property.
    private static readonly ConfigurationProperty _MaxIdleTime =
        new ConfigurationProperty("maxIdleTime",
        typeof(TimeSpan), TimeSpan.FromMinutes(5),
        ConfigurationPropertyOptions.IsRequired);

    // CustomSection constructor.
    public CustomSection()
    {
        // Property initialization
        _Properties =
            new ConfigurationPropertyCollection();

        _Properties.Add(_FileName);
        _Properties.Add(_MaxUsers);
        _Properties.Add(_MaxIdleTime);
    }

    // This is a key customization. 
    // It returns the initialized property bag.
    protected override ConfigurationPropertyCollection Properties
    {
        get
        {
            return _Properties;
        }
    }

    private new bool IsReadOnly
    {
        get
        {
            return _ReadOnly;
        }
    }

    // Use this to disable property setting.
    private void ThrowIfReadOnly(string propertyName)
    {
        if (IsReadOnly)
            throw new ConfigurationErrorsException(
                "The property " + propertyName + " is read only.");
    }

    // Customizes the use of CustomSection
    // by setting _ReadOnly to false.
    // Remember you must use it along with ThrowIfReadOnly.
    protected override object GetRuntimeObject()
    {
        // To enable property setting just assign true to
        // the following flag.
        _ReadOnly = true;
        return base.GetRuntimeObject();
    }


    [StringValidator(InvalidCharacters = " ~!@#$%^&*()[]{}/;'\"|\\",
        MinLength = 1, MaxLength = 60)]
    public string FileName
    {
        get
        {
            return (string)this["fileName"];
        }
        set
        {
            // With this you disable the setting.
            // Remember that the _ReadOnly flag must
            // be set to true in the GetRuntimeObject.
            ThrowIfReadOnly("FileName");
            this["fileName"] = value;
        }
    }

    [LongValidator(MinValue = 1, MaxValue = 1000000,
        ExcludeRange = false)]
    public long MaxUsers
    {
        get
        {
            return (long)this["maxUsers"];
        }
        set
        {
            this["maxUsers"] = value;
        }
    }

    [TimeSpanValidator(MinValueString = "0:0:30",
        MaxValueString = "5:00:0",
        ExcludeRange = false)]
    public TimeSpan MaxIdleTime
    {
        get
        {
            return (TimeSpan)this["maxIdleTime"];
        }
        set
        {
            this["maxIdleTime"] = value;
        }
    }
}

Configuration.Save(ConfigurationSaveMode, Boolean)

  1. forceSaveAll, 会把所有节点保存,但是节点内的key和value按ConfigurationSaveMode的设置保存,如果ConfigurationSaveMode为Modified,那么key和value只会保存修改过的内容。
  2. ConfigurationSaveMode.Full, 每个节点开始位置会增加一个
  3. ConfigurationSaveMode.Minimal,有些节点不会保存,即使是forceSaveAll为true时。

Configuration.SaveAs(String, ConfigurationSaveMode, Boolean)

貌似每次打开配置文件后,只能运行一次lSaveAs操作,如果需要再次SaveAs,必须再打开一次配置文件。

ConfigurationManager.RefreshSection

RefreshSection只有在使用ConfigurationManager.GetSection获取配置数据时,才起作用。如果手动修改配置文件后,没有使用ConfigurationManager.RefreshSection,此后使用ConfigurationManager.GetSection获取的配置数据是不会自动更新的。但是如果运行了RefreshSection,那么使用ConfigurationManager.GetSection获取的数据就会自动更新。对于使用ConfigurationManager.OpenExeConfiguration读取的配置数据,RefreshSection是没有作用的。

ConfigurationManager.AppSettings

获取当前应用程序默认配置的AppSettings Section数据。默认配置存储在项目根目录下的App.config文件中。