Showing posts with label configuration. Show all posts
Showing posts with label configuration. Show all posts

Saturday, 9 March 2013

Unable to load type because it is not public. Except, it is.

TL;DR: if you create constructors for new types derived from ConfigurationSection, you need to create a default constructor too.

While working on some C# configuration I hit this error at runtime:

System.Configuration.ConfigurationErrorsException : An error occurred creating the configuration section handler for databaseSources: Unable to load type 'Sources.SqlServerDataSourceConfiguration, Sources, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it is not public. (C:\Users\Tim\Documents\Code\csharp\Alembic.Metrics\bin\Debug\MetricAgent.exe.config line 7)
  ----> System.TypeLoadException : Unable to load type 'Sources.SqlServerDataSourceConfiguration, Sources, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it is not public.

Confusing, as the code looks like:

public class SqlServerDataSourceConfiguration : ConfigurationSection
{
    public SqlServerDataSourceConfiguration(IEnumerable configs)
    {
        Databases.Add(configs);
    }

    [ConfigurationProperty("databases")]
    public DatabaseElementCollection Databases
    {
        get { return (DatabaseElementCollection)base["databases"]; }
    }
}

And, out of paranoia, ILDasm tells me:

.class public auto ansi beforefieldinit Sources.SqlServerDataSourceConfiguration
extends [System.Configuration]System.Configuration.ConfigurationSection

So, what? Instinct told me it’ll need a public default constructor. Added one and bingo; problem gone.

And soon, I hope I’ll figure out why.

Friday, 5 October 2012

Caught between declarative and programmatic custom configuration element methods

I don’t need to create custom configuration sections for .NET apps very often; whenever I do, it seems like an awkward process.

I hit a new problem recently; only a small one, but sufficiently frustrating that I need to commit it to memory. I was mixing up the two distinct methods for creating the configuration: programmatic, and declarative (or attributed).

The symptom was a  “key has already been added” exception when loading a new application’s configuration. The exception was thrown by configuration elements added to a custom ConfigurationElementCollection.

The error seemed clear: I’d already added a config item with this key. So how do I define the key for an item? Figuring it’d be easy I leant on Intellisense, found the IsKey attribute and thought – great! I can define the properties that make up the key. Happily, I added key properties to my derived ConfigurationElement, suitably attributed.

Daft.

It didn’t work, and it took me a little while to figure out what was going on. I’d forgotten that the ConfigurationElementCollection acts as a factory of sorts – and is also given the responsibility of generating the key. I’d filled out some simple placeholder code to generate an element key there which clearly wasn’t up to the task.

It was only after that, when I looked more deeply into the ConfigurationElementCollection that I realised I’d been mixing mechanisms for expressing the custom configuration. The IsKey attribute was irrelevant, as the mechanism I was using to generate the collection was programmatic.

So, multiple lessons learned: don’t lean on Intellisense without reading the docs; think about the structure of your data, even if it’s a configuration element; and don’t add placeholder code for functions like key generation.