Introduction
I'm a fan of strongly typed definitions where ever possible. It is particularly annoying to use the system ConfigurationManager
class to extract config settings when you are throwing around strings and parsing values to get your configuration straight. Many times you will find yourself writing code like this.
const string APPSETTING_PORTNUMBER = "PortNumber";
int port = int.Parse(ConfigurationManager.AppSettings[APPSETTING_PORTNUMBER]);
Or maybe you don't even bother with the constant, and are guilty of hard-coding those app setting keys right in your code. After my first application that used 50+ of these app settings, I decided to write a library, to make this whole thing a bit easier.
Using the code
With KeyConfig-Net you can create a class that represents your app settings configuration (or other configuration source). KeyConfig-Net is a library comprised of about 200 lines of code, a simple solution to a simple problem. Let's throw up a typical .NET web config configuration file with just the app settings section.
<appSettings>
<add key="HostName" value="localhost"/>
<add key="PortNumber" value="45345"/>
</appSettings>
The following code demonstrates a class that will be used to mirror our configuration file.
public class TestConfigClass
{
[ConfigKey]
public string HostName { get; set; }
[ConfigKey]
public int PortNumber { get; set; }
}
By specifying the TestConfigClass
type as the type parameter, Key-Config will use the default parameterless constructor of TestConfigClass
to create a new instance of TestConfigClass
. It will then scan for the ConfigKey
annotations on public and private instance properties (not static). These properties will be assigned with values from the configuration source. The values will be parsed to the proper types as well. The configuration source is an IConfigSource
implementation, it defines a source of where to get and save configuration values. Key-Config currently comes with just the AppSettingsSource
source but can be extended.
Extracting the configuration from appsettings becomes as simple as this.
var configSettings = ConfigManager<TestConfigClass>.GetConfig(new AppSettingsSource());
Assert.AreEqual("localhost", configSettings.HostName);
Assert.AreEqual(45345, configSettings.PortNumber);
Key-Config can even save app setting values for you.
var source = new AppSettingsSource();
var configSettings = ConfigManager<TestConfigClass>.GetConfig(source);
configSettings.PortNumber = 3423;
ConfigManager<TestConfigClass>.SaveConfig(source, configSettings);
Key-Config annotations also allow you to specify a key value that is different from the property name, as well as indicate if a configuration key is required. In the code below, the Name
property will no longer be assigned to the Name
configuration key in appsettings, it will instead be looking for IpAddress
.
public class TestConfigClass
{
[ConfigKey(KeyName = "IpAddress", Required = true)]
public string Name { get; set; }
[ConfigKey]
public string Occupation { get; set; }
}
You can check if required values are supplied before grabbing any configuration settings by using the following code. Attempting to access a required field with the GetConfig()
method with a required field missing will cause an exception to be thrown.
bool areRequiredFulfilled = ConfigManager<TestConfigClass>.CheckRequired(new AppSettingsSource());
Under The Hood
Key-Config is pretty easy to get an understanding of what is going on under hood.
The solution comprises of the library itself and a very small unit test project. The ConfigManager
class contains the meat of the project. It contains static methods to manipulate configuration sources. Configuration sources are defined via implementing the IConfigSource
interface. You can use this interface to easily extend Key-Config, for example to use a database for configuration settings. Feel free to contribute extensions to the GitHub repository.
public interface IConfigSource
{
bool CanSet { get; }
bool GetCanHandle(Type objTyp);
void SetValue(string key, object value, Type instanceType, Type valueType);
object GetValue(string key, Type instanceType, Type valueType);
}
The ConfigManager
class uses reflection to obtain attribute values from the passed instance type. Reflection is a powerful language feature in C#, it allows you to examine the structure of a type during runtime. The easiest way to enumerate members of a type during runtime is by accessing the members of a Type
object in code.
typeof(TestClass)
Accessing the members of the expression above exposes these potential methods.
These methods return enumerations of type data during runtime, you can examine these members and obtain the attributes they possess, as well as even invoke methods and assign fields and properties, all while your program is running. You can learn more about reflection by reading this MSDN article here: https://msdn.microsoft.com/en-us/library/f7ykdhsy(v=vs.110).aspx
Project Links
Provided are links to the GitHub repository, NuGet package, and documentation for the project.
GitHub:
https://github.com/jhimes144/KeyConfig
Documentation:
https://www.docify.net/Doc/Project_KeyConfigNet
Nuget:
https://www.nuget.org/packages/KeyConfig-Net/