I thought I had this problem licked yesterday, I got it working by change the order of my operations.
- Create new section
- Add elements to section
- Add section to config
- config.Save()
But today I am getting the same error again on the call to config.Save()
I original thought the problem might have been because I added a property toe the section element itself (added an index property) but I backed that out.
My question is why is the section locked? What operations cause a section to be locked. What do I need to do to clear the lock? What is the proper order for updating a section?
Should I only be saving the whole configuration once? I am trying to do a save after modifying each individual section.
OK here is a cut of my code. Except for the FolderSection and FolderElement which are derived form ConfigurationSection and ConfigurationElement. The first call to UpdateFolders() works as expected. The second call fails in the call to config.Save() with the inner exception "ConfigurationSection properties cannot be edited when locked" What should I do between calls?
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();
}
}
}