How do I store a config param as element's body? - c#

What I'm trying to achieve is reading an app.config param that looks like this:
<SomeConfig>
<SomeParam>SomeText</SomeParam>
</SomeConfig>
Code property declaration is like this
[ConfigurationProperty("SomeParam")]
public string SomeParam
{
get { return (string)this["SomeParam"]; }
set { this["SomeParam"] = value; }
}
However, I'm getting this error message on app start: "Property 'SomeParam' is not a ConfigurationElement"
How can I declare it correctly?

Solution:
Your App.config should look like:
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SomeConfig" type="ConfigReader.SomeConfigSection,ConfigReader" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<SomeConfig>
<SomeParam>SomeText</SomeParam>
</SomeConfig>
</configuration>
Program.cs
using System;
using System.Configuration;
using System.Xml;
namespace ConfigReader
{
class Program
{
static void Main(string[] args)
{
SomeConfigSection configSection = ConfigurationManager.GetSection("SomeConfig") as SomeConfigSection;
if (configSection != null)
Console.WriteLine("Value={0}", configSection.SomeParam.Value);
}
}
public class SomeConfigSection : ConfigurationSection
{
[ConfigurationProperty("SomeParam")]
public SomeParamElement SomeParam
{
get { return this["SomeParam"] as SomeParamElement; }
set { this["SomeParam"] = value; }
}
}
public class SomeParamElement:ConfigurationElement
{
protected override void DeserializeElement(XmlReader reader, bool s)
{
Value = reader.ReadElementContentAs(typeof(string), null) as string;
}
public string Value { get; private set; }
}
}
EDIT: Screenshot

I think you will need to override the OnDeserializeUnrecognizedElement . Please take a look at this answer.
Using the above approach, here is how I was able to achieve the result for your requirement:-
My SomeConfigSection class looks like this:-
public class SomeConfigSection : ConfigurationSection
{
[ConfigurationProperty("SomeConfig", IsRequired = true)]
public string SomeConfig
{
get { return (string)base["SomeConfig"]; }
set { base["SomeConfig"] = value; }
}
XElement _SomeParam;
public XElement SomeParam
{
get { return _SomeParam; }
}
protected override bool OnDeserializeUnrecognizedElement(string elementName, System.Xml.XmlReader reader)
{
if (elementName == "SomeParam")
{
_SomeParam = (XElement)XElement.ReadFrom(reader);
return true;
}
else
return base.OnDeserializeUnrecognizedElement(elementName, reader);
}
}
My App.config looks like this:-
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SomeConfig" type="ConfigTest.SomeConfigSection,ConfigTest" />
</configSections>
<SomeConfig>
<SomeParam>SomeText</SomeParam>
</SomeConfig>
</configuration>
In my form, below is how I read the value :-
SomeConfigSection configSection = ConfigurationManager.GetSection("SomeConfig") as SomeConfigSection;
if (configSection != null)
label1.Text= configSection.SomeParam.Value;
Hope This Helps!

Related

Custom app.config section error "Unrecognized element add"

I have a small app that searches my SQL Server database for the given value in all of the fields where it could be used. Part of that is a custom app.config section to hold all of these fields. However I'm getting an error on this line in the app:
var section = (DatabaseFieldSection)ConfigurationManager.GetSection("DatabaseFields");
app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="DatabaseFields" type="PartyFinder.DataAccess.DatabaseFieldSection, DataAccess"/>
</configSections>
<connectionStrings>
<!-- Data removed for security purposes -->
</connectionStrings>
<DatabaseFields>
<add Key="Person.FirstName (SV)" TableName="dbo.Person" ColumnName="FirstName" FieldType="SV" />
</DatabaseFields>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
Classes:
using System;
using System.Configuration;
namespace PartyFinder.DataAccess
{
public class DatabaseFieldElement : ConfigurationElement
{
[ConfigurationProperty("Key", IsKey = true, IsRequired = true)]
public string Key
{
get { return (string)base["Key"]; }
}
[ConfigurationProperty("TableName", IsKey = false, IsRequired = true)]
public string TableName
{
get { return (string)base["TableName"]; }
}
[ConfigurationProperty("ColumnName", IsKey = false, IsRequired = true)]
public string ColumnName
{
get { return (string)base["ColumnName"]; }
}
[ConfigurationProperty("FieldType", IsKey = false, IsRequired = true)]
public string FieldType
{
get { return (string)base["FieldType"]; }
}
}
public class DatabaseFieldSection : ConfigurationSection
{
[ConfigurationProperty("DatabaseFields", IsDefaultCollection = true)]
[ConfigurationCollection(typeof(DatabaseFieldCollection), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
public DatabaseFieldCollection DatabaseFields
{
get { return ((DatabaseFieldCollection)base["DatabaseFields"]); }
}
}
public class DatabaseFieldCollection : ConfigurationElementCollection
{
internal const string PropertyName = "Fields";
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.AddRemoveClearMap;
}
}
protected override string ElementName
{
get
{
return PropertyName;
}
}
protected override bool IsElementName(string elementName)
{
return elementName.Equals(PropertyName, StringComparison.InvariantCultureIgnoreCase);
}
public override bool IsReadOnly()
{
return false;
}
protected override ConfigurationElement CreateNewElement()
{
return new DatabaseFieldElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((DatabaseFieldElement)(element)).Key;
}
public DatabaseFieldElement this[int id]
{
get
{
return (DatabaseFieldElement)BaseGet(id);
}
}
}
}
I have done a ton of searches and nothing has worked so far. Any advice is much appreciated!
I managed to get the following to work in a console app by adding a parent DatabaseConfig node:
The DatabaseFieldSection class:
public class DatabaseFieldSection : ConfigurationSection
{
public static DatabaseFieldSection GetConfig()
{
return (DatabaseFieldSection)System.Configuration.ConfigurationManager.GetSection("DatabaseConfig") ?? new DatabaseFieldSection();
}
[System.Configuration.ConfigurationProperty("DatabaseFields")]
[ConfigurationCollection(typeof(DatabaseFieldCollection), AddItemName = "add")]
public DatabaseFieldCollection DatabaseFields
{
get
{
object o = this["DatabaseFields"];
return o as DatabaseFieldCollection;
}
}
}
And the App.config:
<configSections>
<section name="DatabaseConfig" type="TestEnvironment.DBConfig.DatabaseFieldSection, TestEnvironment"/>
</configSections>
<DatabaseConfig>
<DatabaseFields>
<add Key="Person.FirstName (SV)" TableName="dbo.Person" ColumnName="FirstName" FieldType="SV" />
</DatabaseFields>
</DatabaseConfig>
Usage:
var config = DatabaseFieldSection.GetConfig();
It seems as though the config <section /> cannot be the same as the config element collection name. e.g DatabaseFields, it needs to be:
Section > Collection > Items
Or:
DatabaseConfig > DatabaseFields > add

Configuration of the application

I am trying setting up application configuration. Problem is that nothing is readed from the configuration. I am using this code:
Sections:
public class TownSection : ConfigurationSection
{
public static TownSection.GetConfig()
{
return (TownSection)System.Configuration.ConfigurationManager
.GetSection("TownSection") ?? new TownSection();
}
[System.Configuration.ConfigurationProperty("TownProperties")]
[ConfigurationCollection(typeof(TownProperties), AddItemName = "TownProperty")]
public TownProperties TownProperties
{
get
{
object o = this["TownProperties"];
return o as TownProperties;
}
}
}
List of the entities:
public class TownProperties: ConfigurationElementCollection
{
public TownProperty this[int index]
{
get
{
return base.BaseGet(index) as TownProperty ;
}
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
public new TownProperty this[string responseString]
{
get { return (TownProperty)BaseGet(responseString); }
set
{
if (BaseGet(responseString) != null)
{
BaseRemoveAt(BaseIndexOf(BaseGet(responseString)));
}
BaseAdd(value);
}
}
protected override System.Configuration.ConfigurationElement CreateNewElement()
{
return new TownProperty();
}
protected override object GetElementKey(System.Configuration.ConfigurationElement element)
{
return ((TownProperty)element).Name;
}
}
Entity:
public class TownProperty: ConfigurationElement
{
[ConfigurationProperty("Name", IsRequired = true)]
public string Name
{
get
{
return this["Name"] as string;
}
}
[ConfigurationProperty("Distance", IsRequired = true)]
public string Distance
{
get
{
return this["Distance"] as string;
}
}
}
Configuration in app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="TownSection">
<section
name="TownSection"
type="App.Configurations.TownSection"
allowLocation="true"
allowDefinition="Everywhere" />
</sectionGroup>
</configSections>
<TownSection>
<TownProperties>
<TownProperty Name="A" Distance="1.8"/>
<TownProperty Name="B" Distance="5.8"/>
</TownProperties>
</TownSection>
in code:
var config = TownSection.GetConfig();
foreach(TownProperty item in config.TownProperties) /// cycle is skipped
{
Console.WriteLine(item.Name);
Console.WriteLine(item.Distance);
}
What could be the problem?
I've changed couple of things in xml and that works.
1.Removed Section group tag
2.Added assembly name in section tag's type attribute. In format (Full type name, Assembly name)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section
name="TownSection"
type="App.Configurations.TownSection, App.Configurations"
allowLocation="true"
allowDefinition="Everywhere" />
</configSections>
<TownSection>
<TownProperties>
<TownProperty Name="A" Distance="1.8"/>
<TownProperty Name="B" Distance="5.8"/>
</TownProperties>
</TownSection>
</configuration>

ConfigurationErrorsException occurred

I want to create a custom configuration for C# application. The app.config likes:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="location" type ="FolderConfigSection.LocationConfig, FolderConfigSection"/>
</configSections>
<location>
<folders>
<add folder ="C:\Test1"/>
<add folder ="C:\Test2" />
<add folder ="C:\Test3" />
</folders>
</location>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
So I created two classes.
namespace FolderConfigSection
{
public class LocationConfig : ConfigurationSection
{
[ConfigurationProperty("folders")]
public string Folder
{
get { return base["folder"] as string; }
set { base["folder"] = value; }
}
}
}
And
namespace FolderConfigSection
{
public class FolderCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new FolderElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((FolderElement)element).Environment;
}
}
public class FolderElement : ConfigurationElement
{
[ConfigurationProperty("folder", IsRequired = true)]
public string Environment
{
get { return (string)this["folder"]; }
set { this["folder"] = value; }
}
}
}
But I got an exception in my Program.cs
public class Program
{
public static void Main(string[] args)
{
LocationConfig _locationConfig = (LocationConfig)ConfigurationManager.GetSection("location");
string firstFolder = _locationConfig.Folder;
}
}
The exception is The section name 'location' is reserved for <location> sections.
Also I want to list all folders.
I'm restating what #Tim has answered in his comments.
Do not use location as section name. It is already reserved for <location> element configuration. Just use other name, such as locationConfig.
Change the type of Folder property in LocationConfig class from String to FolderCollection. For clarity, you should probably change the property name Folder to its plural form Folders.
To list all the folders in LocationConfig, you just need to iterate the Folders collection property. You might also want to implement indexer on FolderCollection class, for an indexed access to Folders property, .
Putting it all in code:
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="locationConfig" type ="FolderConfigSection.LocationConfig, FolderConfigSection"/>
</configSections>
<locationConfig>
<folders>
<add folder ="C:\Test1"/>
<add folder ="C:\Test2" />
<add folder ="C:\Test3" />
</folders>
</locationConfig>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
LocationConfig
namespace FolderConfigSection
{
using System.Configuration;
public class LocationConfig : ConfigurationSection
{
// Change the property type to FolderCollection, and
// change the property name to `Folders` for clarity
[ConfigurationProperty("folders")]
public FolderCollection Folders
{
get { return base["folders"] as FolderCollection; }
// the setter property isn't really needed here
// set { base["folders"] = value; }
}
}
public class FolderCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new FolderElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((FolderElement)element).Environment;
}
// indexer
public FolderElement this[int index]
{
get { return BaseGet(index) as FolderElement; }
}
}
public class FolderElement : ConfigurationElement
{
[ConfigurationProperty("folder", IsRequired = true)]
public string Environment
{
get { return (string)this["folder"]; }
set { this["folder"] = value; }
}
}
}
Program.cs
public class Program
{
static void Main(string[] args)
{
var locationConfig = (LocationConfig)ConfigurationManager.GetSection("locationConfig");
foreach (FolderElement folder in locationConfig.Folders)
{
// List all folders
Console.WriteLine(folder.Environment);
}
// The first folder using indexer property
Console.WriteLine(locationConfig.Folders[0].Environment);
}
}

ConfigurationManager.GetSection returns null when section type is a different assembly

I'm trying to read from a configuration section in app.config which has been added by way of a reference to NServiceBus.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="UnicastBusConfig"
type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="MessageForwardingInCaseOfFaultConfig"
type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
<section name="TestConfig"
type="Console1.UnicastBusConfigSection, Console1" />
</configSections>
<startup>
<supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.5" />
</startup>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
<UnicastBusConfig>
<MessageEndpointMappings></MessageEndpointMappings>
</UnicastBusConfig>
<TestConfig>
<MessageEndpointMappings></MessageEndpointMappings>
</TestConfig>
</configuration>
I have the following classes defined for the UnicastBusConfig section:
public class UnicastBusConfigSection : ConfigurationSection
{
[ConfigurationProperty(MessageEndPointMappingsName)]
[ConfigurationCollection(typeof(MessageEndPointMappingsCollection), AddItemName = "add")]
public MessageEndPointMappingsCollection MessageEndPointMappings { get { return (MessageEndPointMappingsCollection)base[MessageEndPointMappingsName]; } }
}
public class MessageEndPointMappingsCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new MessageEndPointMappingsElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((MessageEndPointMappingsElement)element).Messages;
}
public void Add(MessageEndPointMappingsElement element)
{
BaseAdd(element);
}
}
public class MessageEndPointMappingsElement : ConfigurationElement
{
[ConfigurationProperty("Messages", IsRequired = true)]
public string Messages
{
get { return (string)this["Messages"]; }
set { this["Messages"] = value; }
}
[ConfigurationProperty("Endpoint", IsRequired = true)]
public string Endpoint
{
get { return (string)this["Endpoint"]; }
set { this["Endpoint"] = value; }
}
}
When I call ConfigurationManager.GetSection for the UnicastBusConfig section it returns null, yet for the TestConfig section I get an objet back ok...
var unicastBusConfigSection = ConfigurationManager.GetSection("UnicastBusConfig") as UnicastBusConfigSection;
var unicastBusConfigSection = ConfigurationManager.GetSection("TestConfig") as UnicastBusConfigSection;

Unrecognized element "Item" in config file with custom config section

I have a custom config which is based on some classes. My problem is that I get an error saying that a config element is unrecognized. The class is as follows:
[ConfigurationCollection(typeof(SectionItem), AddItemName = "Item", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class Sections : ConfigurationElementCollection
{
public SectionItem this[int index]
{
get { return BaseGet(index) as SectionItem; }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public new SectionItem this[string response]
{
get { return (SectionItem)BaseGet(response); }
set
{
if (BaseGet(response) != null)
{
BaseRemoveAt(BaseIndexOf(BaseGet(response)));
}
BaseAdd(value);
}
}
protected override ConfigurationElement CreateNewElement()
{
return new SectionItem();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((SectionItem)element).Key;
}
}
And the SectionItem class:
public class SectionItem : ConfigurationElement
{
[ConfigurationProperty("key", IsRequired = true, IsKey = true)]
public string Key
{
get { return this["key"] as string; }
}
}
If I add a configuration property of type SectionItems in the Sections class that won't work for me, because I want to have multiple SectonItems inside the Section tag in the config file. I've searched for solutions but everything I've found didn't do the trick with this.
For a better understanding of what I'm trying to achieve this is how my config looks:
<configuration>
<configSections>
<section name="AdminConfig" type="XmlTest.AdminConfig, XmlTest"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<AdminConfig>
<Field name="field1" key="12345" path="asd"/>
<Section>
<Item key="12345"/>
<Item key="54321"/>
</Section>
</AdminConfig>
</configuration>
OK so I've found the problem. Although the Sections class had this [ConfigurationCollection(typeof(SectionItem), AddItemName = "Item", CollectionType = ConfigurationElementCollectionType.BasicMap)] I had to annotate the property in the ConfigurationSection class, as follows:
[ConfigurationProperty("Section")]
[ConfigurationCollection(typeof(Sections), AddItemName = "Item")]
public Sections Sections
{
get
{
return (Sections)this["Section"];
}
}
Now the items are recognized and stuff is working properly.

Categories