锁定时无法编辑 ConfigurationSection 属性

ConfigurationSection properties cannot be edited when locked

我以为我昨天解决了这个问题,我通过改变我的操作顺序让它工作了。

  1. 创建新部分
  2. 向部分添加元素
  3. 将部分添加到配置
  4. config.Save()

但是今天我在调用 config.Save()

时再次遇到同样的错误

我最初认为问题可能是因为我在 section 元素本身添加了一个 属性(添加了一个索引 属性),但我反对了。

我的问题是为什么该部分被锁定?什么操作导致部分被锁定。我需要做什么来清除锁定?更新部分的正确顺序是什么?

我应该只保存整个配置一次吗?我正在尝试在修改每个单独的部分后进行保存。

好的,这是我的代码的一部分。除了从 ConfigurationSection 和 ConfigurationElement 派生的 FolderSection 和 FolderElement。这 第一次调用 UpdateFolders() 按预期工作。第二次调用在调用 config.Save() 时失败,内部异常 "ConfigurationSection properties cannot be edited when locked" 我应该在两次调用之间做什么?

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using System.IO;
using System.Configuration;

// using Common.Core;
// using Common.Config;

namespace Common.Test
{
    public class FolderElement : ConfigurationElement
    {
        protected const string NameKey = "name";
        protected const string VolumeKey = "volume";
        protected const string PathKey = "path";
        protected const string selectedKey = "selected";
        protected const string activeKey = "active";

    [ConfigurationProperty(NameKey, DefaultValue = "", IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)base[NameKey]; }
        set { base[NameKey] = value; }
    }

    [ConfigurationProperty(VolumeKey, DefaultValue = "", IsKey = false, IsRequired = false)]
    public string VolumeLabel
    {
        get { return (string)base[VolumeKey]; }
        set { base[VolumeKey] = value; }
    }

    [ConfigurationProperty(PathKey, DefaultValue = "", IsKey = false, IsRequired = true)]
    public string Path
    {
        get { return (string)base[PathKey]; }
        set { base[PathKey] = value; }
    }

    [ConfigurationProperty(selectedKey, DefaultValue = "false", IsKey = false, IsRequired = false)]
    public bool Selected
    {
        get { return (bool)base[selectedKey]; }
        set { base[selectedKey] = value; }
    }

    [ConfigurationProperty(activeKey, DefaultValue = "true", IsKey = false, IsRequired = false)]
    public bool Active
    {
        get { return (bool)base[activeKey]; }
        set { base[activeKey] = value; }
    }
}

[ConfigurationCollection(typeof(FolderElement))]
public class FolderCollection : ConfigurationElementCollection
{
    internal const string _elementName = "elements";

    protected override string ElementName
    {
        get { return _elementName; }
    }

    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
    }

    protected override bool IsElementName(string elementName)
    {
        return elementName.Equals(_elementName, StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool IsReadOnly()
    {
        return false;
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new FolderElement();
    }

    /// <summary>
    /// Return key value for element.
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((FolderElement)element).Name;
    }

    /// <summary>
    /// Default index property.
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public FolderElement this[int index]
    {
        get { return (FolderElement)BaseGet(index); }
    }


    /// <summary>
    /// Returns content element by name.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public FolderElement GetElementByName(string name)
    {
        return (FolderElement)BaseGet(name);
    }


    public IEnumerable<FolderElement> Elements
    {
        get
        {
            for (int index = 0; index < this.Count; index++) yield return (FolderElement)BaseGet(index);
        }
    }

    /// <summary>
    /// Add an element to the collection
    /// </summary>
    /// <param name="element"></param>
    public void AddElement(FolderElement element)
    {
        BaseAdd(element);
    }


}

public class FolderSection : ConfigurationSection
{

    // Attribute argument must be a constant expression.
    protected const string _elementsTag = "elements";

    [ConfigurationProperty(_elementsTag, Options = ConfigurationPropertyOptions.IsDefaultCollection)]
    public FolderCollection Elements
    {
        get { return ((FolderCollection)(base[_elementsTag])); }
        set { base[_elementsTag] = value; }
    }

}


[TestClass]
public class TestConfig
{
    private string _appName = "Test";
    private string _appFolder = null;

    private static string _exec = Path.GetFileName(Environment.GetCommandLineArgs()[0]);


    public string AppFolder
    {
        get
        {
            return (_appFolder == null)
                ? _appFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "myProjects", _appName)
                : _appFolder;
        }
    }


    public ExeConfigurationFileMap GetFileMap()
    {

        var fileMap = new ExeConfigurationFileMap();
        fileMap.ExeConfigFilename = Path.Combine(AppContext.BaseDirectory, _exec + ".config");
        fileMap.RoamingUserConfigFilename = Path.Combine(AppFolder, "App.config");
        fileMap.LocalUserConfigFilename = Path.Combine(AppFolder, "App.config");

        return fileMap;

    }


    [TestMethod]
    public void SaveConfigTest()
    {
        var fileMap = GetFileMap();
        var userConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.PerUserRoamingAndLocal);

        UpdateFolders(userConfig, "dstFolders", 0, @"C:\Temp", @"C:\Users\Darrel", @"C:\Users\Darrel\MyDocuments");
        UpdateFolders(userConfig, "srcFolders", 0, @"C:\Temp", @"C:\Users\Angela", @"C:\Users\Angela\MyDocuments");

    }

    public void UpdateFolders(Configuration config, string sectionName, int selectedIndex, params string[] folders)
    {
        bool addSection = false;

        var section = config.GetSection(sectionName) as FolderSection;
        if (section == null)
        {
            section = new FolderSection();
            section.SectionInformation.AllowDefinition = ConfigurationAllowDefinition.Everywhere;
            section.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
            section.SectionInformation.ForceSave = true;
            section.SectionInformation.ForceDeclaration(true);
            addSection = true;
        }

        int index = 0;
        section.Elements.EmitClear = true;
        foreach (var folder in folders)
        {
            string Name = "folder" + (index + 1).ToString();
            // string label = FileHelper.GetVolumeLabel(folder);
            string label = "OS";
            var element = section.Elements.GetElementByName(Name) as FolderElement;
            if (element != null)
            {
                element.Path = folder;
                element.VolumeLabel = label;
            }
            else
            {
                element = new FolderElement() { Name = Name, Path = folder, VolumeLabel = label };
                section.Elements.AddElement(element);
            }
            element.Selected = (selectedIndex == index);
            index++;
        }

        // Add elements to section before adding section to config.Sections.
        if (addSection) config.Sections.Add(sectionName, section);

        config.Save();

    }
}

}

我至少可以在测试用例中解决这个问题,如果我将保存从更新中提升 class 所以它只执行一次。

 [TestMethod]
    public void SaveConfigTest()
    {
        var fileMap = GetFileMap();
        var userConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.PerUserRoamingAndLocal);

        UpdateFolders(userConfig, "dstFolders", 0, @"C:\Temp", @"C:\Users\Darrel", @"C:\Users\Darrel\MyDocuments");
        UpdateFolders(userConfig, "srcFolders", 0, @"C:\Temp", @"C:\Users\Angela", @"C:\Users\Angela\MyDocuments");

        userconfig.Save();
    }

重新打开配置似乎也适用于测试用例,但我可以发誓这就是我在原始代码中所做的。

[TestMethod]
    public void SaveConfigTest()
    {
        var fileMap = GetFileMap();
        var userConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.PerUserRoamingAndLocal);

        UpdateFolders(userConfig, "dstFolders", 0, @"C:\Temp", @"C:\Users\Darrel", @"C:\Users\Darrel\MyDocuments");
        userconfig.Save();

        userConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.PerUserRoamingAndLocal);
        UpdateFolders(userConfig, "srcFolders", 0, @"C:\Temp", @"C:\Users\Angela", @"C:\Users\Angela\MyDocuments"); 
        userconfig.Save();
    }