Creating a custom Configuration - c#

I created a customer configuration class Reports. I then created another class called "ReportsCollection". When I try and do the "ConfigurationManager.GetSection()", it doesn't populate my collection variable. Can anyone see any mistakes in my code?
Here is the collection class:
public class ReportsCollection : ConfigurationElementCollection
{
public ReportsCollection()
{
}
protected override ConfigurationElement CreateNewElement()
{
throw new NotImplementedException();
}
protected override ConfigurationElement CreateNewElement(string elementName)
{
return base.CreateNewElement(elementName);
}
protected override object GetElementKey(ConfigurationElement element)
{
throw new NotImplementedException();
}
public Report this[int index]
{
get { return (Report)BaseGet(index); }
}
}
Here is the reports class:
public class Report : ConfigurationSection
{
[ConfigurationProperty("reportName", IsRequired = true)]
public string ReportName
{
get { return (string)this["reportName"]; }
//set { this["reportName"] = value; }
}
[ConfigurationProperty("storedProcedures", IsRequired = true)]
public StoredProceduresCollection StoredProcedures
{
get { return (StoredProceduresCollection)this["storedProcedures"]; }
}
[ConfigurationProperty("parameters", IsRequired = false)]
public ParametersCollection Parameters
{
get { return (ParametersCollection)this["parameters"]; }
}
[ConfigurationProperty("saveLocation", IsRequired = true)]
public string SaveLocation
{
get { return (string)this["saveLocation"]; }
}
[ConfigurationProperty("recipients", IsRequired = true)]
public RecipientsCollection Recipients
{
get { return (RecipientsCollection)this["recipients"]; }
}
}
public class StoredProcedure : ConfigurationElement
{
[ConfigurationProperty("storedProcedureName", IsRequired = true)]
public string StoredProcedureName
{
get { return (string)this["storedProcedureName"]; }
}
}
public class StoredProceduresCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
throw new NotImplementedException();
}
protected override ConfigurationElement CreateNewElement(string elementName)
{
return base.CreateNewElement(elementName);
}
protected override object GetElementKey(ConfigurationElement element)
{
throw new NotImplementedException();
}
public StoredProcedure this[int index]
{
get { return (StoredProcedure)base.BaseGet(index); }
}
}
}
And here is the very straight-forward code to create the variable:
ReportsCollection reportsCollection = (ReportsCollection) System.Configuration.ConfigurationManager.GetSection("ReportGroup");
EDIT
Added App.Config
<configSections>
<sectionGroup name="ReportGroup">
<section name="Reports" type="ReportsGenerator.ReportsCollection"/>
</sectionGroup>
</configSections>
<ReportGroup>
<Reports name="DailyIssues" SaveLocation="">
<StoredProcedures>
<add StoredProcedureName="RPTDailyIssues" />
<add StoredProcedureName="RPTNoIssues" />
</StoredProcedures>
<Parameters>
<add ParameterName="#FromDate" />
<add ParameterName="#ThruDate" />
</Parameters>
<Recipients>
<add RecipientName="me#mycompany.com"
</Recipients>
</Reports>
</ReportGroup>

You should check out Jon Rista's three-part series on .NET 2.0 configuration up on CodeProject.
Unraveling the mysteries of .NET 2.0 configuration
Decoding the mysteries of .NET 2.0 configuration
Cracking the mysteries of .NET 2.0 configuration
Highly recommended, well written and extremely helpful!
Also, there's a Configuration Section Designer add-in for Visual Studio which is extremely helpful for creating custom configuration sections - it features a visual designer that creates all the necessary XSD and classes in the background.
Marc

I didn't write configuration sections for awhile, but out of the top of my head your CreateNewElement() methods throw exceptions.. Make them at least return dummy entries, maybe that's the reason.. )
Also, show the reportsCollection element in your web.config.. is it registered correctly?

Related

Try to create a custom section in Web.config

I am trying to create a custom section in my web.config. I have a custom class and a declaration section in my web.config.
when I run my code however I am getting this error "...does not inherit from System.Configuration.IConfigurationSectionHandler'."
MSDN documentation states that this Interface is now deprecated.
I don't understand what cold be happening.
FYI I used this (http://blogs.perficient.com/microsoft/2017/01/4-easy-steps-to-custom-sections-in-web-config/ as my guide to create my custom section.
Here is my web.config
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name ="BDKConfigs" type="SPS.CardDecryption.Services.BDKConfigs" allowLocation="true" allowDefinition="Everywhere" />
</configSections>
Here is my custom section in the web.config
<BDKConfigs>
<!--collection-->
<BDK>
<!--elements-->
<add name="IDTechPublicBDK" value="0123456789ABCDEFFEDCBA9876543210"/>
<add name="IDTechProdBDK" value=""/>
</BDK>
</BDKConfigs>
this is my custom class
using System.Configuration;
namespace myNameSpace
{
//This class reads the defined config section (if available) and stores it locally in the static _Config variable.
public class BDKConfigs
{
public static BDKConfigsSection _Config = ConfigurationManager.GetSection("BDKConfigs") as BDKConfigsSection;
public static BDKElementCollection GetBDKGroups()
{
return _Config.BDKConfigs;
}
}
public class BDKConfigsSection : ConfigurationSection
{
//Decorate the property with the tag for your collection.
[ConfigurationProperty("BDK")]
public BDKElementCollection BDKConfigs
{
get { return (BDKElementCollection)this["BDK"]; }
}
}
//Extend the ConfigurationElementCollection class.
//Decorate the class with the class that represents a single element in the collection.
[ConfigurationCollection(typeof(BDKElement))]
public class BDKElementCollection : ConfigurationElementCollection
{
public BDKElement this[int index]
{
get { return (BDKElement)BaseGet(index); }
set
{
if (BaseGet(index) != null)
BaseRemoveAt(index);
BaseAdd(index, value);
}
}
protected override ConfigurationElement CreateNewElement()
{
return new BDKElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((BDKElement)element).Name;
}
}
//Extend the ConfigurationElement class. This class represents a single element in the collection.
//Create a property for each xml attribute in your element.
//Decorate each property with the ConfigurationProperty decorator. See MSDN for all available options.
public class BDKElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
[ConfigurationProperty("queryString", IsRequired = false)]
public string Value
{
get { return (string)this["Value"]; }
set { this["Value"] = value; }
}
}
}
The issue was that I had the wrong type specified in the web.config. When I changed my web.config to
type="SPS.CardDecryption.Services.BDKConfigsSection , worked like a charm.
I have updated answer:
public class BDKConfigsSection : ConfigurationSection
{
[ConfigurationProperty("BDK")]
public BDKElementCollection BDKConfigs
{
get { return (BDKElementCollection) base["BDK"]; }
}
}
[ConfigurationCollection(typeof(BDKElement))]
public class BDKElementCollection : ConfigurationElementCollection
{
public BDKElement this[int index]
{
get { return (BDKElement)BaseGet(index); }
set
{
if (BaseGet(index) != null)
BaseRemoveAt(index);
BaseAdd(index, value);
}
}
protected override ConfigurationElement CreateNewElement()
{
return new BDKElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((BDKElement)element).Name;
}
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMapAlternate; }
}
protected override string ElementName => "BDKItem";
}
public class BDKElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
[ConfigurationProperty("queryString", IsRequired = false)]
public string Value
{
get { return (string)this["queryString"]; }
set { this["queryString"] = value; }
}
}
that one working fine :
<BDKConfigsSection>
<BDK>
<BDKItem name="IDTechPublicBDK" queryString="0123456789ABCDEFFEDCBA9876543210"/>
<BDKItem name="IDTechProdBDK" queryString=""/>
</BDK> </BDKConfigsSection>

Cannot get custom configuration section to work in app.config

I followed a tutorial on Stackoverflow to add a custom configuration section to my exe's config file, however on calling it, it is returning null. It's not even getting into the static constructors so something is clearly wrong, but I can't see what.
Here is my config file and the section I wish to find.
<configuration>
<appSettings>
</appSettings>
<configSections>
<section name="PresetFilters" type="ImageTool.PresetFiltersConfiguration, ImageTool" />
</configSections>
<PresetFilters>
<add key="Default,-20,0,0,0,0" />
<add key="No Change,0,0,0,0,0" />
<add key="Dark Photo,10,10,0,0,-10" />
</PresetFilters>
</configuration>
I call it like this:
PresetFiltersConfiguration pf = (PresetFiltersConfiguration)ConfigurationManager.GetSection("PresetFilters");
and it returns null and doesn't even enter my class or class statics. Here's the code. Any help would be appreciated. Thanks.
public class PresetFiltersConfiguration : ConfigurationSection
{
private static ConfigurationPropertyCollection properties;
private static ConfigurationProperty propPresets;
static PresetFiltersConfiguration()
{
propPresets = new ConfigurationProperty(null, typeof(PresetFiltersElementCollection),
null,
ConfigurationPropertyOptions.IsDefaultCollection);
properties = new ConfigurationPropertyCollection { propPresets };
}
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public PresetFiltersElementCollection PresetFilter
{
get
{
return this[propPresets] as PresetFiltersElementCollection;
}
}
}
public class PresetFiltersElementCollection : ConfigurationElementCollection
{
public PresetFiltersElementCollection()
{
properties = new ConfigurationPropertyCollection();
}
private static ConfigurationPropertyCollection properties;
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.BasicMap;
}
}
protected override string ElementName
{
get
{
return "add";
}
}
protected override ConfigurationElement CreateNewElement()
{
return new PresetFiltersElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
var elm = element as PresetFiltersElement;
if (elm == null) throw new ArgumentNullException();
return elm.KeyName;
}
}
public class PresetFiltersElement : ConfigurationElement
{
private static ConfigurationPropertyCollection properties;
private static ConfigurationProperty propKey;
protected override ConfigurationPropertyCollection Properties
{
get
{
return properties;
}
}
public PresetFiltersElement()
{
propKey = new ConfigurationProperty("key", typeof(string),
null,
ConfigurationPropertyOptions.IsKey);
properties = new ConfigurationPropertyCollection { propKey };
}
public PresetFiltersElement(string keyName)
: this()
{
KeyName = keyName;
}
public string KeyName
{
get
{
return this[propKey] as string;
}
set
{
this[propKey] = value;
}
}
}
You need something like this in your app.config, otherwise the application won't know how to process your new section.
<configSections>
<sectionGroup name="pageAppearanceGroup">
<section
name="PresetFilters"
type="PresetFiltersConfiguration"
allowLocation="true"
allowDefinition="Everywhere"
/>
</sectionGroup>
</configSections>
After applying the fixes it worked, but the actual fault is to do with it not working for class libraries, and I've created a new question for this.
Thanks.

Custom App.Config Section - Unrecognized element Exception

I'm trying to create a Custom Section in the app.config and run into the following exception:
ConfigurationErrorsException
Unrecognized element 'EncryptedUserCredential'. (C:\My Documents\Hachette.CRM\test_app_appsettings\bin\Debug\test_app_appsettings.vshost.exe.Config line 11)
Now I'm at a complete loss. I have stepped into the RegisterEncryptedUserCredentialsConfig.GetConfig(), and found the Section is null from the propery RegisterEncryptedUserCredentialsConfig.EncryptedUserCredentials. I have also checked all the usual suspects I when investigating online, like:
Making sure the type includes the assembly name in the app.config configSection when declaring the custom section.
is at the beginning of in the app.config.
The custom section is written in:
Class Library
C#/.NET 4.0.
I'm at a loss and think I have been staring at it too long the weekend gone and need some fresh eyes!
For ease I have added all the code from the C# class library here.
Here is the app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="EncryptedUserCredentials"
type="Hachette.Common.CustomConfigSections.RegisterEncryptedUserCredentialsConfig, Hachette.Common"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<EncryptedUserCredentials>
<EncryptedUserCredential userName="garethB" password="1235#"/>
<EncryptedUserCredential userName="webService" password="123ffff5#"/>
</EncryptedUserCredentials>
</configuration>
Here is the EncryptedUserCredential ConfigurationElement:
public class EncryptedUserCredential : ConfigurationElement
{
[ConfigurationProperty("userName", IsRequired = true)]
public string UserName
{
get
{
return this["userName"] as string;
}
}
[ConfigurationProperty("password", IsRequired = true)]
public string Password
{
get
{
return this["password"] as string;
}
}
}
Here is the EncryptedCredentials ConfigurationElementCollection:
public class EncryptedUserCredentials : ConfigurationElementCollection
{
public EncryptedUserCredential this[int index]
{
get
{
return base.BaseGet(index) as EncryptedUserCredential;
}
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
public new EncryptedUserCredential this[string responseString]
{
get
{
return (EncryptedUserCredential)BaseGet(responseString);
}
set
{
if (BaseGet(responseString) != null)
{
BaseRemoveAt(BaseIndexOf(BaseGet(responseString)));
}
BaseAdd(value);
}
}
protected override ConfigurationElement CreateNewElement()
{
return new EncryptedUserCredential();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((EncryptedUserCredential)element).UserName;
}
}
Here is the RegisterEncryptedUserCredentialsConfig ConfigurationSection:
public class RegisterEncryptedUserCredentialsConfig : ConfigurationSection
{
public static RegisterEncryptedUserCredentialsConfig GetConfig()
{
//var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
return (RegisterEncryptedUserCredentialsConfig)System.Configuration.ConfigurationManager.GetSection("EncryptedUserCredentials") ?? new RegisterEncryptedUserCredentialsConfig();
}
[System.Configuration.ConfigurationProperty("EncryptedUserCredentials", IsDefaultCollection=true,IsRequired=true)]
[ConfigurationCollection(typeof(EncryptedUserCredentials), AddItemName="EncryptedUserCredential")]
public EncryptedUserCredentials EncryptedUserCredentials
{
get
{
object o = this["EncryptedUserCredentials"];
return o as EncryptedUserCredentials;
}
}
}
All of the above live in namespace:
namespace Hachette.Common.CustomConfigSections
And in the following Assembly:
It's not possible for the root element to be the collection holder. So you should code up your configuration to match this structure (note I've picked a name for the root element to match your namespace, but feel free to choose anything you like):
<hachette>
<EncryptedUserCredentials>
<EncryptedUserCredential userName="garethB" password="1235#"/>
<EncryptedUserCredential userName="webService" password="123ffff5#"/>
</EncryptedUserCredentials>
</hachette>
This means your configuration hierarchy will have a root ConfigSection which in turn contains a ConfigurationElementCollection that contains all of the ConfigurationElement objects.
Here is an example article on how you can write it: http://www.abhisheksur.com/2011/09/writing-custom-configurationsection-to.html

App.config: custom configuration nested sections

I have found a great example for custom configuration handler and tried to use it for my own implementation.
I have set up App.config like this:
<configSections>
<section name="DocumentationSettings" type="ConfigHandler.DocumentationSettings,Settings"/>
</configSections>
<DocumentationSettings>
<DocumentationSections>
<DocumentationSection Id="AAA">
<SectionDescription Value="SectionDescriptionAAA"/>
</DocumentationSection>
<DocumentationSection Id="BBB">
<SectionDescription Value="SectionDescriptionBBB"/>
</DocumentationSection>
<DocumentationSection Id="CCC">
<SectionDescription Value="SectionDescriptionCCC"/>
</DocumentationSection>
</DocumentationSections>
</DocumentationSettings>
I use this code to access my custom configuration:
DocumentationSettings documentationSettings = ConfigurationManager.GetSection("DocumentationSettings") as DocumentationSettings;
foreach (DocumentationSectionConfigElement section in (documentationSettings.DocumentationSections.Sections))
{
Console.WriteLine(section.Id);
Console.WriteLine(section.SectionDescription.Properties.Value);
}
First 'Console.WriteLine' works perfect.
So I have the following problems and implementation related questions:
I get error on second 'Console.WriteLine', error: Unrecognized attribute 'Value'. I have put "public SectionDescription SectionDescription" since "DocumentationSectionConfigElement" Class exposes property access, but I might be wrong, I tried first to put it into "DocumentationSectionCollection" but I don't know how to implement it there and for me it seems that "DocumentationSectionCollection" only implements "Collection" logic.
I want to access "fields" either both like this:
section.Id
section.SectionDescription.Value
or like this:
section.Properties.Id
section.SectionDescription.Properties.Value
I see that "Collection" allows to use these properties directly using indexer methods like this:
public DocumentationSectionConfigElement this[int index]
But I can't implement indexer method on "SectionDescription" class, because it is a single section not a collection, so this "Properties" name persists when I access fields.
What do I need to add to be able to use LINQ on these configuration objects?
I mean like this:
(documentationSettings.DocumentationSections.Sections).Select(x => x.Id)
Are there any really good examples of complex XML structure configuration handler? From those which I found there were mostly simple structures like these:
but no any example of complex structure like this:
<section>
<subSections>
<subSection name="111">
<Description Value="AAA"></Description>
<Headers>
<Header type="Main">
<Properties>
<Property name="Property1"/>
<Property name="Property2"/>
<Property name="Property3"/>
</Properties>
</Header>
</Headers>
</subSection>
</subSections>
</section>
which is more close to real scenarios when you need to better organize application configuration.
What is the point of "sectionGroup" tag in "configSections" if "Custom Configuration Handler" works and it is enough with one "section" registered ?
Why all this stuff so complex? I have spent so much time these "custom configuration" things that shouldn't be so complex I believe. Aren't there any Visual Studio Add-ins that handle this stuff and generate code based on XML configuration structure?
Here is my Configuration Handler implementation:
public class DocumentationSettings : ConfigurationSection
{
[ConfigurationProperty("DocumentationSections")]
public DocumentationSections DocumentationSections
{
get { return (DocumentationSections)base["DocumentationSections"]; }
}
}
public class DocumentationSections : ConfigurationElement
{
[ConfigurationProperty("", IsDefaultCollection = true)]
public DocumentationSectionCollection Sections
{
get { return (DocumentationSectionCollection)base[""]; }
}
}
public class SectionDescription : ConfigurationElement
{
[ConfigurationProperty("SectionDescription")]
public new SectionDescriptionConfigElement Properties
{
get { return (SectionDescriptionConfigElement)base["SectionDescription"]; }
}
}
public class DocumentationSectionCollection : ConfigurationElementCollection
{
public DocumentationSectionCollection()
{
DocumentationSectionConfigElement details = (DocumentationSectionConfigElement)CreateNewElement();
if (details.Id != "")
{
Add(details);
}
}
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override ConfigurationElement CreateNewElement()
{
return new DocumentationSectionConfigElement();
}
protected override Object GetElementKey(ConfigurationElement element)
{
return ((DocumentationSectionConfigElement)element).Id;
}
public DocumentationSectionConfigElement this[int index]
{
get { return (DocumentationSectionConfigElement)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
new public DocumentationSectionConfigElement this[string name]
{
get { return (DocumentationSectionConfigElement)BaseGet(name); }
}
public int IndexOf(DocumentationSectionConfigElement details)
{
return BaseIndexOf(details);
}
public void Add(DocumentationSectionConfigElement details)
{
BaseAdd(details);
}
protected override void BaseAdd(ConfigurationElement element)
{
BaseAdd(element, false);
}
public void Remove(DocumentationSectionConfigElement details)
{
if (BaseIndexOf(details) >= 0)
BaseRemove(details.Id);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(string name)
{
BaseRemove(name);
}
public void Clear()
{
BaseClear();
}
protected override string ElementName
{
get { return "DocumentationSection"; }
}
}
public class DocumentationSectionConfigElement : ConfigurationElement
{
[ConfigurationProperty("Id", IsRequired = true, IsKey = true)]
[StringValidator(InvalidCharacters = " ~!##$%^&*()[]{}/;’\"|\\")]
public string Id
{
get { return (string)this["Id"]; }
set { this["Id"] = value; }
}
[ConfigurationProperty("Name", IsRequired = false)]
public string Name
{
get { return (string)this["Name"]; }
set { this["Name"] = value; }
}
[ConfigurationProperty("SectionDescription")]
public SectionDescription SectionDescription
{
get { return ((SectionDescription)base["SectionDescription"]); }
}
}
public class SectionDescriptionConfigElement : ConfigurationElement
{
[ConfigurationProperty("Value", IsRequired = true)]
public string Value
{
get { return (string)this["Value"]; }
set { this["Value"] = value; }
}
}
Since no activity here, I will try answering my questions one by one:
Found this nice article that describes a lot of things and shows somewhat complex example of custom configuration implementation.
I found this great tool - ".NET Configuration Code Generator", that does exactly what I wanted - it takes XML structure and generates custom configuration code.

how to have custom attribute in ConfigurationElementCollection?

for configuration as following
<MyCollection default="one">
<entry name="one" ... other attrubutes />
... other entries
</MyCollection>
when implement a MyCollection, what should i do for the "default" attribute?
Let's suppose you have this .config file:
<configuration>
<configSections>
<section name="mySection" type="ConsoleApplication1.MySection, ConsoleApplication1" /> // update type & assembly names accordingly
</configSections>
<mySection>
<MyCollection default="one">
<entry name="one" />
<entry name="two" />
</MyCollection>
</mySection>
</configuration>
Then, with this code:
public class MySection : ConfigurationSection
{
[ConfigurationProperty("MyCollection", Options = ConfigurationPropertyOptions.IsRequired)]
public MyCollection MyCollection
{
get
{
return (MyCollection)this["MyCollection"];
}
}
}
[ConfigurationCollection(typeof(EntryElement), AddItemName = "entry", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class MyCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new EntryElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return ((EntryElement)element).Name;
}
[ConfigurationProperty("default", IsRequired = false)]
public string Default
{
get
{
return (string)base["default"];
}
}
}
public class EntryElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public string Name
{
get
{
return (string)base["name"];
}
}
}
you can read the configuration with the 'default' attribute, like this:
MySection section = (MySection)ConfigurationManager.GetSection("mySection");
Console.WriteLine(section.MyCollection.Default);
This will output "one"
I don't know if it's possible to have a default value in a ConfigurationElementCollection. (it doesn't seen to have any property for default value).
I guess you have to implement this by yourself. Look at the example below.
public class Repository : ConfigurationElement
{
[ConfigurationProperty("key", IsRequired = true)]
public string Key
{
get { return (string)this["key"]; }
}
[ConfigurationProperty("value", IsRequired = true)]
public string Value
{
get { return (string)this["value"]; }
}
}
public class RepositoryCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new Repository();
}
protected override object GetElementKey(ConfigurationElement element)
{
return (element as Repository).Key;
}
public Repository this[int index]
{
get { return base.BaseGet(index) as Repository; }
}
public new Repository this[string key]
{
get { return base.BaseGet(key) as Repository; }
}
}
public class MyConfig : ConfigurationSection
{
[ConfigurationProperty("currentRepository", IsRequired = true)]
private string InternalCurrentRepository
{
get { return (string)this["currentRepository"]; }
}
[ConfigurationProperty("repositories", IsRequired = true)]
private RepositoryCollection InternalRepositories
{
get { return this["repositories"] as RepositoryCollection; }
}
}
Here's the XML config:
<myConfig currentRepository="SQL2008">
<repositories>
<add key="SQL2008" value="abc"/>
<add key="Oracle" value="xyz"/>
</repositories>
</myConfig>
And then, at your code, you access the default item using the following:
MyConfig conf = (MyConfig)ConfigurationManager.GetSection("myConfig");
string myValue = conf.Repositories[conf.CurrentRepository].Value;
Of course, the MyConfig class can hide the details of accessing the Repositories and CurrentRepository properties. You can have a property called DefaultRepository (of type Repository) in MyConfig class to return this.
This may be a bit late but may be helpful to others.
It is possible but with some modification.
ConfigurationElementCollection inherits ConfigurationElement as such "this[string]" is available in ConfigurationElement.
Usually when ConfigurationElementCollection is inherited and implemented in another class, the "this[string]" is hidden with "new this[string]".
One way to get around it is to create another implementation of this[] such as "this[string, string]"
See example below.
public class CustomCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new CustomElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CustomElement)element).Name;
}
public CustomElement this[int index]
{
get { return (CustomElement)base.BaseGet(index); }
set
{
if (BaseGet(index) != null)
BaseRemoveAt(index);
BaseAdd(index, value);
}
}
// ConfigurationElement this[string] now becomes hidden in child class
public new CustomElement this[string name]
{
get { return (CustomElement)BaseGet(name); }
}
// ConfigurationElement this[string] is now exposed
// however, a value must be entered in second argument for property to be access
// otherwise "this[string]" will be called and a CustomElement returned instead
public object this[string name, string str = null]
{
get { return base[name]; }
set { base[name] = value; }
}
}
If you want to genericize it, this should help:
using System.Configuration;
namespace Abcd
{
// Generic implementation of ConfigurationElementCollection.
[ConfigurationCollection(typeof(ConfigurationElement))]
public class ConfigurationElementCollection<T> : ConfigurationElementCollection
where T : ConfigurationElement, IConfigurationElement, new()
{
protected override ConfigurationElement CreateNewElement()
{
return new T();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((IConfigurationElement)element).GetElementKey();
}
public T this[int index]
{
get { return (T)BaseGet(index); }
}
public T GetElement(object key)
{
return (T)BaseGet(key);
}
}
}
Here's the interface referenced above:
namespace Abcd
{
public interface IConfigurationElement
{
object GetElementKey();
}
}

Categories