app.config - configuration system failed to initialize with custom section - c#

I've got a web api where I've added a custom section into the web.config as per this link: https://msdn.microsoft.com/en-us/library/2tw134k3.aspx. My web.config looks as follows:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please
visit https://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<configSections>
<sectionGroup name="productGroup">
<section
name="product"
type="myProject.Stuff.Api.ProductSection"
allowLocation="true"
allowDefinition="Everywhere"
/>
</sectionGroup>
</configSections>
<appSettings>
<!-- various app settings -->
</appSettings>
<productGroup>
<product name="my name" id="1" />
<product name="my name 2" id="2" />
</productGroup>
<!-- other standard elements -->
</configuration>
I added in the configSections and the productGroup. I then define a c# class as ProductSection as follows:
using System.Configuration;
namespace myProject.Stuff.Api
{
public class ProductSection : ConfigurationSection
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return (string)this["name"];
}
set
{
this["name"] = value;
}
}
[ConfigurationProperty("id", IsRequired = true)]
public int Id
{
get
{
return (int)this["id"];
}
set
{
this["id"] = value;
}
}
}
}
I've copied the 2 sections across to my app.config in my test project, but when I now try and debug a test I get the failed to initialize error. When I comment out the productGroup section it then stops complaining. What have I done wrong?
UPDATE
As a side note I ended up structuring it a little more simply. As my 'product' sections only needed a name and id they lent themselves to key value pairs as per appSettings. So I created a section like this:
<configSections>
<section name="productGroup"
type="System..Configuration.NameValueSectionHandler"
allowLocation="true"
allowDefinition="Everywhere"/>
</configSections>
Note that I changed the type. My productGroup then looked like this:
<productGroup>
<add key="product1" value="1" />
<add key="product2" value="2" />
</productGroup>
I then could remove the ProductSection class altogether and just reference my group of products like this:
var products = ConfigurationManager.GetSection("productGroup") as NameValueCollection;
if (products.AllKeys.Contains(myProduct))
{
var myValue = products[myProduct];
}

I notice 2 things
A configuration section can only appear 1 time within a configuration file.
The full initialization exception shows:
System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize --->
System.Configuration.ConfigurationErrorsException: Sections must only appear once per config file.
This means you can only have 1 product section:
<productGroup>
<product name="my name" id="1" />
</productGroup>
If you need multiple, you need to declare multiple sections with unique section names:
<configuration>
<sectionGroup name="productGroup">
<section name="product" type="myProject.Stuff.Api.ProductSection" />
<section name="product2" type="myProject.Stuff.Api.ProductSection" />
</sectionGroup>
<!-- Other configuration elements -->
<productGroup>
<product name="my name" id="1" />
<product2 name="my name 2" id="2" />
</productGroup>
</configuration>
It is a best practice to declare the section in app/web.config with its fully qualified assemblyname,
which includes the name of the assembly (without file extension).
This is a must if the class/section is defined in an external assembly; here ProductionSection is defined in an assembly other than the one of the main unittest.
Declare the section as below in the App.config file of your unittest project.
(Replace NameOfTheAssemblyContainingTheProductSectionClass with the name of your assembly.)
<section
name="product"
type="myProject.Stuff.Api.ProductSection, NameOfTheAssemblyContainingTheProductSectionClass"
/>

Related

How to programmatically read the custom config files in asp.net mvc

In the root folder of my ASP.NET MVC 5 I have two config files. one is the default web.config file and the second one is department.config.
The content of the department.config file is:
<department>
<add key="dept1" value="xyz.uvw.rst" />
<add key="dept2" value="abc.def.ghi" />
<department>
How to read the department.config file ?
I want to get a collection of values under <department> in this config file.
Edit: Web.config has <department configSource="reports.config" />
so, how to read the configSource file in asp.net mvc ?
Edit:
<configuration>
<configSections>
<section name="departments"
type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false"
requirePermission="false" />
In your web.config, you can specify other files that the built-in ConfigurationManager can easily access. For example, we decided that we wanted to separate connection strings and application setting into separate files. You can do this by putting this in your web.config:
<appSettings configSource="appsettings.config" />
Then you can access these values in the 'regular' way
ConfigurationManager.AppSettings["KeyHere"]
Same thing with connection strings...
Why not use the appSettings section in your web.config? These are easy to read using ConfigurationManager object.
In your web.config, find the appSettings section:
<appSettings>
<add key="dept1" value="xyz.uvw.rst"/>
Then in your class where you want to read it, import the correct namespace:
using System.Configuration;
And then read the value easily, like so:
var dept1 = ConfigurationManager.AppSettings.Get("dept1");
If you have to have it in a separate config, you might consider creating a class for it, I'll post up an example of that shortly.
edit1: here is a quick example of how to do your own custom config
first, define the config class:
using System;
using System.Configuration;
namespace WebApplication2
{
public class MyConfig : ConfigurationSection
{
private static readonly MyConfig ConfigSection = ConfigurationManager.GetSection("MyConfig") as MyConfig;
public static MyConfig Settings
{
get
{
return ConfigSection;
}
}
[ConfigurationProperty("Dept1", IsRequired = true)]
public string Dept1
{
get
{
return (string)this["Dept1"];
}
set
{
this["Dept1"] = value;
}
}
[ConfigurationProperty("Dept2", IsRequired = true, DefaultValue = "abc.def.ghi")]
public string Dept2
{
get
{
return (string)this["Dept2"];
}
set
{
this["Dept2"] = value;
}
}
// added as example of different types
[ConfigurationProperty("CheckDate", IsRequired = false, DefaultValue = "7/3/2014 1:00:00 PM")]
public DateTime CheckDate
{
get
{
return (DateTime)this["CheckDate"];
}
set
{
this["CheckDate"] = value;
}
}
}
}
Then, set it up in your web.config file:
<configuration>
<configSections>
<section name="MyConfig" type="WebApplication2.MyConfig, WebApplication2" />
</configSections>
<MyConfig Dept1="xyz.uvw.rst" Dept2="abc.def.ghi" />
...
</configuration>
And then you can call it very easily, along with strong-typing and support for many types:
var dept1 = MyConfig.Settings.Dept1;
var dept2 = MyConfig.Settings.Dept2;
// strongly-typed
DateTime chkDate = MyConfig.Settings.CheckDate;
That's how I would do it. Use the built-in stuff and create a class for it. Easy to do config transforms with, easy to read, and easy to use.
This is an old question but in the event someone needs to know... First geekzsters answer lays out how to write a config class. Then you specify a custom Config Section and give it a configSource in a separate file.
<configuration>
<configSections>
<section name="myCustomSection" type="MyNamespace.MyCustomType" requirePermission="false" />
</configSections>
</configuration>
<myCustomSection configSource="myConfigDir\myFile.config" />
Then in your custom config file you write a normal xml config
<?xml version="1.0" encoding="utf-8"?>
<myCustomSection>
<myCustomType>
<add name="pro1" value="abc" />
<add name="prop2" value="cde" />
<add name="prop3" value="efg" />
</myCustomType>
</myCustomSection>
The simplest way to read configuration File other then Web config is to define file you want to read as follows:
webConfig
<appSettings file="TestFile.config">
<add key="webpages:Version" value="3.0.0.0"/>
<add key="webpages:Enabled" value="false"/>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
TestFile.Config
<appSettings>
<add key="test" value="testData"/>
</appSettings>
Above we define the file we want to read configuration from in Webconfig. thus using ConfigurationManager.AppSettings['test'] you can read the value from your newly created custom config file.

Spring.Net. ContextRegistry.GetContext() exception, cannot configure Common.Logging

I cannot get the IApplication context for my console app
I get an exception with this detail:
The type initializer for 'Spring.Context.Support.ContextRegistry' threw an exception.
With inner exception:
Could not configure Common.Logging from configuration section 'common/logging
There's clearly something basic I've not hooked up, but I'm not sure what.
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
IApplicationContext ctx = ContextRegistry.GetContext();
}
}
}
And my app.config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net">
<description>An example that demonstrates simple IoC features. </description>
</objects>
</spring>
</configuration>
Spring.Net uses Common Logging as facility for logging, you have to add the logging configuration to your app.config and the proper library to the referenced assemblies.
<configuration>
<configSections>
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
</configSections>
<common>
<logging>
<factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
<arg key="level" value="DEBUG" />
<arg key="showLogName" value="true" />
<arg key="showDataTime" value="true" />
<arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" />
</factoryAdapter>
</logging>
</common>
</configuration>
http://netcommon.sourceforge.net/docs/1.2.0/reference/html/logging.html#logging-declarative-config
The type initializer for 'Spring.Context.Support.ContextRegistry'
threw an exception
This is valueable information and Spring.net is really good at providing additional information. Whenever Spring.net throws something, be sure to read the InnerException.
WHen I edit my config I get the messages: Could not find schema
information for the attribute #. for # = 'uri', 'context', 'resource'
and 'spring'
This is normal if you didn't install the schemas. You can download the schemas at their site and find additional information in their docs. Please note that this is optional and spring runs without those schemas.

How to use ConfigurationManager.AppSettings with a custom section?

I need to get "http://example.com" from using App.config file.
But at the moment I am using:
string peopleXMLPath = ConfigurationManager.AppSettings["server"];
I cannot get the value.
Could you point out what I am doing wrong?
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<configSections>
<section name="device" type="System.Configuration.SingleTagSectionHandler" />
<section name="server" type="System.Configuration.SingleTagSectionHandler" />
</configSections>
<device id="1" description="petras room" location="" mall="" />
<server url="http://example.com" />
</configuration>
I think you need to get the config section, and access that:
var section = ConfigurationManager.GetSection("server") as NameValueCollection;
var value = section["url"];
And you also need to update your config file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<configSections>
<section name="device" type="System.Configuration.NameValueSectionHandler" />
<section name="server" type="System.Configuration.NameValueSectionHandler" />
</configSections>
<device>
<add key="id" value="1" />
<add key="description" value="petras room" />
<add key="location" value="" />
<add key="mall" value="" />
</device>
<server>
<add key="url" value="http://example.com" />
</server>
</configuration>
Edit: As CodeCaster mentioned in his answer, SingleTagSectionHandler is for internal use only. I think NameValueSectionHandler is the preferred way to define config sections.
The SingleTagSectionHandler documentation says:
This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
You can retrieve it as a HashTable and access its entries using Configuration.GetSection():
Hashtable serverTag = (Hashtable)ConfigurationManager.GetSection("server");
string serverUrl = (string)serverTag["url"];
string peopleXMLPath = ConfigurationManager.AppSettings["server"];
gets the value from the appSettings part of the app.config file but you are storing your value in
<server url="http://example.com" />
Either put the value in the appSettings section as below or retrieve the value from its current location.
You need to add a key value pair to your config's appSettings section. As below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="server" value="http://example.com" />
</appSettings>
</configuration>
Your reading code is correct but you should probably check for null. If the code fails to read the config value the string variable will be null.
You're defining a configuration section instead of a value in AppSettings. You can simply add your setting to AppSettings:
<appSettings>
... may be some settings here already
<add key="server" value="http://example.com" />
</appSettings>
Custom config sections are typically used for more complicated configurations (e.g. multiple values per key, non-string values, etc.
If you want to get the value from the app settings your appsetting element in configuration file must have a key.
define your sever value as mentioned below under configuration section:
<configuration>
<appSettings>
<add key="server" value="http://example.com" />
</appSettings>
...
...
...
</configuration>
Now execute below code line to get the server url:
string peopleXMLPath = ConfigurationManager.AppSettings["server"].ToString();

Why controler does not go in to Create function?

I have some custome section defined in seperate file, but when i call
ConfigurationManager.GetSection("Group/Group1/screen1")
controler does not go in to Create method and above code return null, whats wrong? anything is missing ?
web.Config:
<configSections>
<sectionGroup name="Group">
<section name="Group1" type="Handler"
allowLocation="true"
allowDefinition="Everywhere">
</section>
</sectionGroup>
</configSections>
<Group>
<Group1 configSource="folder1\custom.config" />
</Group>
Custom.config:
<?xml version="1.0"?>
<Group>
<Group1>
<Screen1>
<Property1>0</Property1>
<Property2>1</Property2>
</Screen1>
<Screen2>
<Property1>1</Property1>
<Property2>Create</Property2>
</Screen2>
</Group1>
<Group2>
<Screen1>
<Property1>0</Property1>
<Property2>1</Property2>
</Screen1>
<Screen2>
<Property1>1</Property1>
<Property2>Create</Property2>
</Screen2>
</Group2>
</Group>
Handler:
public class Handler: IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
**debugger**
// Some processing
// return object
}
}
I think your custom.config should start at the Group1 element, rather than the Group element, or the configSource should be applied to the Group. Either way, the root element of the referenced config file should be the same element type as configSource is applied to.
So, it sounds like what you want in your web.config is:
<Group configSource="folder1\custom.config" />
Whenever you use the configSource, the elements must match on both sides, e.g. if you have:
<Spargle configSource="place1.config" />
Then the root element of place1.config has to be a <Spargle>:
<?xml version="1.0"?>
<Spargle>
<Floom/>
</Spargle>

App.config - custom section not working

I recently started building a console version of a web application. I copied my custom sections from my web.config. to my app.config. When I go to get config information i get this error:
An error occurred creating the configuration section handler for x/y: Could not load type 'x' from assembly 'System.Configuration
The line that it is not liking is:
return ConfigurationManager.GetSection("X/Y") as Z;
Anyone run into something like this?
I was able to add
<add key="IsReadable" value="0"/>
in the appSettings and read it.
Addition:
I do actually have this defined about the custom section:
<configSections>
<sectionGroup name="x">
<section name="y" type="zzzzz"/>
</sectionGroup>
</configSections>
it sounds like your config-section handler is not defined
<configSection>
<section
name="YOUR_CLASS_NAME_HERE"
type="YOUR.NAMESPACE.CLASSNAME, YOUR.NAMESPACE, Version=1.1.0.0, Culture=neutral, PublicKeyToken=PUBLIC_TOKEN_ID_FROM_ASSEMBLY"
allowLocation="true"
allowDefinition="Everywhere"
/>
</configSection>
I had this identical issue recently. I created a custom sectiongroup for a web application(ran just fine), but when I ported this layer to a console app, the sectiongroup was failing.
You were correct in your question regarding how much of the "type" is required in your section definition. I've modified your configuration section with an example below:
<configSection>
<section
name="yourClassName"
type="your.namespace.className, your.assembly"
allowLocation="true"
allowDefinition="Everywhere" />
</configSection>
You'll notice, the type now has class name followed by assembly name. This is required for interaction outside of a web environment.
NOTE: Assembly name does not necessarily equal your namespace(for a given section).
If you want a custom config handler you have to define the class and reference it as shown by Steven Lowe. You can inherit from predefined handlers, or you can just use the value/key pair that is offered in appSetting section as you noted.
At the top of your file you require to have configSection tag with inside the section.
You can have sectionGroup too. Example:
<configuration>
<configSections>
<sectionGroup name="x">
<section name="y" type="a, b"/>
</sectionGroup>
<configSections>
</configuration>
This class works as a general custom configuration section handler for any type...
public class XmlConfigurator : IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
if (section == null) return null;
Type sectionType = Type.GetType((string)(section.CreateNavigator()).Evaluate("string(#configType)"));
XmlSerializer xs = new XmlSerializer(sectionType);
return xs.Deserialize(new XmlNodeReader(section));
}
}
In your app.config, add
<section name="NameofConfigSection" type="NameSpace.XmlConfigurator, NameSpace.Assembly"/>
And in the configuration section element, add an attribute to specify the type you want the root element deserialized into..
<?xml version="1.0" encoding="utf-8" ?>
<NameofConfigSection configType="NameSpace.NameofTypeToDeserializeInto, Namespace.Assembly" >
...
</NameofConfigSection>

Categories

Resources