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.