How many times do you have to write a line of code like this?
var portString =
Environment.GetEnvironmentVariable("port");
portString = string.IsNullOrEmpty(portString)
? ConfigurationManager.AppSettings["port"]
: portString;
int port;
if (!Int32.TryParse(portString, out port)) {
throw new Exception("No port, no bananas!");
}
(Well, maybe not many times but hey, I hope you got the point!)
What if I can use something as simple as this:
public interface ISampleConfiguration {
int Port { get; }
}
// yada yada yada
var configuration =
new ConfigurationBuilder<ISampleConfiguration>()
.FromAppSettings()
.FromEnvironment()
.Build();
Now you can set the value in your AppSettings section in your configuration file or setting the value in your environment variables.
Given a simple configuration setting like this:
<configuration>
<appSettings>
<add key="logging:key" value="abcd12345" />
<add key="server-url" value="http://example.org" />
<add key="server" value="http://boo.org" />
</appSettings>
</configuration>
We can partition configuration in three different configuration interfaces:
public interface ILoggingConfiguration {
string Key { get; }
}
public interface IServerConfiguration {
string Url { get; }
}
public interface IConfiguration {
string Url { get; }
}
We can grab the configuration in two ways:
- Using the configuration builder
var logCfg = new ConfigurationBuilder<ILoggingConfiguration>().WithPrefix("logging").Build();
var srvCfg = new ConfigurationBuilder<IServerConfiguration>().WithPrefix("server", "-").Build();
var cfg = new ConfigurationBuilder<IConfiguration>().Build();
- Using attributes
[KeyPrefix("logging:")]
public interface ILoggingConfiguration {
string Key { get; }
}
[KeyPrefix("server-")]
public interface IServerConfiguration {
string Url { get; }
}
public interface IConfiguration {
string Url { get; }
}
We can provide default values using the DefaultValue
Attribute. Right now, if a value is not present in any of the sources it will throw an exception in the moment the configuration class is build, except if you have a default value attribute applied to the property.
TypeConverters
are supported, well, in fact, anything supported by Castle.DynamicDictionary
is supported too. Just decorate the property with a TypeConverter
attribute providing your custom TypeConverter and that's all, happiness is guaranteed.
Heavily inspired in this blog post from Krzysztof Koźmic. Thanks mate, you are awesome.