I'm developing a windows service that reads information from the app.config at start-up which should allow us to change internal thread configuration without redeploying the service.
I created some custom configuration sections and elements as follows (implementation omitted):
public class MyConfigurationSection
{
[ConfigurationProperty("threads")]
[ConfigurationCollection(typeof(MyThreadCollection), AddItemName="addThread")>
public MyThreadCollection threads { get; }
}
public class MyThreadCollection
{
protected override void CreateNewElement();
protected override object GetElementKey(ConfigurationElement element);
}
public class MyThreadElement
{
[ConfigurationProperty("active", DefaultValue=true, IsRequired=false)>
public bool active { get; set; }
[ConfigurationProperty("batchSize", DefaultValue=10, IsRequired=false)>
public int batchSize { get; set; }
[ConfigurationProperty("system", IsRequired=true)>
public string system { get; set; }
[ConfigurationProperty("department", IsRequired=true)>
public string department { get; set; }
[ConfigurationProperty("connection", IsRequired=true)>
public MyThreadConnectionElement connection { get; set; }
}
public class MyThreadConnectionElement
{
[ConfigurationProperty("server", IsRequired=true)>
public string server { get; set; }
[ConfigurationProperty("database", IsRequired=true)>
public string database { get; set; }
[ConfigurationProperty("timeout", DefaultValue=15, IsRequired=false)>
public int timeout { get; set; }
}
Then I add some elements to the app.config as follows:
<configurationSection>
<threads>
<addThread
active="True"
batchSize="50"
system="MySystem1"
department="Department1">
<connectionString
server="MyServer"
database="Database1" />
</addThread>
<addThread
active="True"
batchSize="30"
system="MySystem2"
department="Department2">
<connectionString
server="MyServer"
database="Database2" />
</addThread>
</threads>
</configurationSection>
Everything works - configuration is read, threads are created, and the processes run.
The problem is, I would like both these threads to have the same system
name/value -- both should be MySystem
-- but when I do that and run the program, I get a The entry 'MySystem' has already been added.
exception.
I figured it might be because a property has to be explicitly configured to allow duplicates, but I don't know how and I couldn't find a property of the ConfigurationProperty
class that might allow that, other than IsKey
, but from its description it didn't seem like the answer, and trying it didn't solve the problem. Am I on the right track here?
Initially the system
property was named name
and I though that just maybe any property named name
is treated as a unique identifier, so I changed it to system
but it didn't change anything.
I tried the <clear />
tag as some other, similar posts suggested, without success.
Do I need to add another hierarchy to the configuration section -- Config -> Department -> Thread instead of Config -> Thread? I'd prefer to not take this approach.
Thanks for any and all input.
I actually found the problem and solution quite some time ago, but forgot to post the answer; thanks @tote for reminding me.
When implementing the ConfigurationElementCollection
class, the GetElementKey(ConfigurationElement)
method can be overridden. Without immediately realising what the method is for I overrode it and simply returned the system
property value, and, since more than one configuration element had the same system name, technically they had the same key, which is why the error occurred.
The solution for me was to return the system
and the department
values as system.department
which resulted in unique keys.