The Problem We have a lot of C# code that wants to access some kind of configuration, and this is all done through: ConfigurationManager.AppSettings["SomeSettingOrOther"] For example, we had a class, that had the following code. CurrencyConversion public class CurrencyConversion{ Currency GetDefaultCurrency() { // get the config setting string configCurrency = ConfigurationManager.AppSettings["MarketCurrency"]; // return the equivalent Enum return CurrencyFromString(configCurrency); }} This code has several issues. Its dependency on the setting is implicit (ie we can’t know this by looking at the public interface of the class, we have to look in to the internals). MarketCurrency It can throw exceptions if the config setting is missing or badly formatted, and we will only find this out when running this particular bit of code. There may be other parts of the code that also use this config setting, and that will repeat the conversion of the string to the Enum and any error handling. Possibly it is using the wrong config setting (or reusing an existing setting for the sake of convenience), and should more properly be using . We can’t know this by looking at the code, and the knowledge resides only in developers heads. DefaultCurrency Testing is difficult, as we have to set up the ConfigurationManager, and we probably have some trial and error whilst working out what configuration is required. The configuration source ( ) is hard coded, and could vary over the codebase (that is with some methods using ConfigurationManager and some methods reading Environment Variables) ConfigurationManager There were higher level problems too. These calls were spread throughout the code, sometimes deep in shared libraries, and it was impossible to know which bits of needed which settings (without reading all of the code). code This meant it was difficult to validate that a config file contained all the information it needed, and that nobody dared to remove config settings. This in turn led to our config files to become increadingly bloated and confusing. The Solution To solve these problems we moved to using interfaces to define our configuration. If we refactor the example code above to take its configuration via an interface we get the following (in real life, being as there is only one setting, you might decide just to pass it in directly, but bear with me). public interface ICurrencyConversionConfiguration{ Currency DefaultCurrency;} public class CurrencyConversion{ readonly ICurrencyConversionConfiguration configuration; public CurrencyConversion(ICurrencyConversionConfiguration configuration) { Contract.Requires(configuration != null); this.configuration = configuration; } Currency GetDefaultCurrency() { return configuration.DefaultCurrency; }} This code has the following improvements Its dependency on is now explicit. It is not possible to create the class without it. DefaultCurrency The dependency on is satisfied through constructor injection. DefaultCurrency It is easy to Mock when testing. ICurrencyConversionConfiguration The name is consistent. The responsibility for reading and parsing the configuration has been removed. To handle the responsibility for reading and parsing the configuration we add the code below. This relies on a simple class, which you can see on GitHub at . Configuration https://github.com/resgroup/configuration public class EconomicModelConfiguration : ICurrencyConversionConfiguration { readonly Configuration configuration; public EconomicModelConfiguration(Configuration configuration) { Contract.Requires(configuration != null); this.configuration = configuration; Validate(); } void Validate() => using (var validator = configuration.CreateValidator) validator.Check(() => DefaultCurrency); public string DefaultCurrency => configuration.GetEnum<Currency>(MethodBase.GetCurrentMethod());} The configuration class itself is instantiated with a Configuration Source, which reads from environment variables in the example below. This makes it easy to adhere to 12 Factor App recommendations ( ). https://12factor.net/config new Configuration(new GetFromEnvironment()); This has the following improvements The config settings are checked when the class is created (which should be at the entry point of the application), so any config problems are flushed out immediately. The code to convert from string to Currency is centralised. The configuration source is encapsulated. If we move another class to use the new configuration system, we get something like this. public class EconomicModelConfiguration : ICurrencyConversionConfiguration, IConcreteCostConfiguration { readonly Configuration configuration; public EconomicModelConfiguration(Configuration configuration) { Contract.Requires(configuration != null); this.configuration = configuration; Validate(); } void Validate() { using (var validator = configuration.CreateValidator) { validator.Check(() => DefaultCurrency); validator.Check(() => DefaultConcreteCost); } } public string DefaultCurrency => configuration.GetEnum<Currency>(MethodBase.GetCurrentMethod()); public double DefaultConcreteCost => configuration.GetDouble(MethodBase.GetCurrentMethod());} This process continues as we move more classes over to the new system, and has the benefit that setting up Inversion of Control is easy, as we can just register with all the interfaces that it implements. EconomicModelConfiguration Legacy Code Like any mature software team, we have some legacy code, some of which is not ready to be created via Inversion of Control. For these classes we create a static Configuation class public static class EconomicModelConfigurationStatic{ readonly static EconomicModelConfiguration base = new EconomicModelConfiguration(); public static IEconomicModelConfiguration Settings => base;} In the Legacy code, we then replace ConfigurationManager.AppSettings["SomeSettingOrOther"] with EconomicModelConfigurationStatic.Settings.SomeSettingOrOther This gets us a lot of the benefits of the new system, with only very minor and easy changes to the existing code. Conclusions Encapsulating configuration logic in this way, and providing configuration through an interface, has the following benefits. There are no , so any misspellings will be caught at compile time magic strings Refactoring (eg ), can be used and guarantee that all instances are updated tools rename All references to an item of configuration can be easily found using Visual Studio Code is explicit about the configuration it requires, and can define only the subset of the configuration that it needs Configuration files can be checked to see if they contain all the required information Configuration files can be checked to see if they contain any surplus information Configuration logic, such as defaults and conversion is handled centrally Configuration items are guaranteed to have the same name in the config file and in the code If you would like to use it, there is a , and the . nuget package available source is on GitHub