All Projects → davidwhitney → System.Configuration.Abstractions

davidwhitney / System.Configuration.Abstractions

Licence: MIT license
Injectable, mockable, extensible, configuration for .NET

Programming Languages

C#
18002 projects
Batchfile
5799 projects

Projects that are alternatives of or similar to System.Configuration.Abstractions

Bigbash
A converter that generates a bash one-liner from an SQL Select query (no DB necessary)
Stars: ✭ 230 (+447.62%)
Mutual labels:  converter
java-xml-to-json
👾 convert XML to a structure-preserving JSON representation
Stars: ✭ 15 (-64.29%)
Mutual labels:  converter
bank2ynab
Easily convert and import your bank's statements into YNAB. This project consolidates other conversion efforts into one universal tool.
Stars: ✭ 197 (+369.05%)
Mutual labels:  converter
BatchEncoder
BatchEncoder is an audio files conversion software.
Stars: ✭ 145 (+245.24%)
Mutual labels:  converter
guepard
flash to html5 converter, as3 to javascript translator
Stars: ✭ 58 (+38.1%)
Mutual labels:  converter
slackdown
A simple Slack message text formatting to HTML code converter.
Stars: ✭ 27 (-35.71%)
Mutual labels:  converter
Retrofit Logansquare
A Converter implementation using LoganSquare JSON serialization for Retrofit 2.
Stars: ✭ 224 (+433.33%)
Mutual labels:  converter
dnglab
Camera RAW to DNG file format converter
Stars: ✭ 103 (+145.24%)
Mutual labels:  converter
csv2vcf
🔧 Simple script in python to convert CSV files to VCF
Stars: ✭ 66 (+57.14%)
Mutual labels:  converter
readable-web-to-node-stream
Converts a Web-API readable-stream into a Node readable-stream.
Stars: ✭ 33 (-21.43%)
Mutual labels:  converter
cpc
Text calculator with support for units and conversion
Stars: ✭ 89 (+111.9%)
Mutual labels:  converter
objectify-css
CLI for converting CSS rules to JavaScript style objects
Stars: ✭ 46 (+9.52%)
Mutual labels:  converter
fp-units
An FP-oriented library to easily convert CSS units.
Stars: ✭ 18 (-57.14%)
Mutual labels:  converter
Mpv Webm
Simple WebM maker for mpv, with no external dependencies.
Stars: ✭ 234 (+457.14%)
Mutual labels:  converter
caffe weight converter
Caffe-to-Keras weight converter. Can also export weights as Numpy arrays for further processing.
Stars: ✭ 68 (+61.9%)
Mutual labels:  converter
Kepubify
Fast, standalone EPUB to KEPUB converter CLI app / library (and a few other utilities).
Stars: ✭ 225 (+435.71%)
Mutual labels:  converter
Audiblex
Audible audio book converter which actually works!
Stars: ✭ 26 (-38.1%)
Mutual labels:  converter
ZPL-Printer-Emulator-SDK
Convert, Preview & Render raw ZPL commands to PNG, JPG & PDF from .NET
Stars: ✭ 29 (-30.95%)
Mutual labels:  converter
converter-go
Convert AsyncAPI documents from older to newer versions with Golang
Stars: ✭ 17 (-59.52%)
Mutual labels:  converter
json2table
Converts JSON to an HTML table
Stars: ✭ 52 (+23.81%)
Mutual labels:  converter

System.Configuration.Abstractions Build status

  • Introduction
  • Installation
  • Getting started
  • Features
    • Generic typed helper methods for retrieving typed config values
    • Configuration Interceptors
    • Configuration Substitution Interceptor
  • Contributing
  • Credits

In most projects, you're going to have some configuration. In .NET projects, it'll probably start in your app.config or web.config file.

However, if you love TDD, you'll likely have notice that all of the built in configuration classes are horribly un-testable. They all revolve around static references to System.Configuration.ConfigurationManager, and don't really have any interfaces, so in every project, you end up wrapping them into something like "IAppSettingsWrapper", in order to write tests.

After writing these wrappers several thousand times, and being inspired by the excellent "System.IO.Abstractions" package, we've put together a standardised set of wrappers around these core framework classes.

If you want

  • to mock/stub/whatever out your App/Web.config files
  • to assert that the values from configuration are really configuring your application
  • to add custom hooks around loading configuration values
  • stronger typing

The this is for you.

Installation

Via NuGet:

	PM> Install-Package System.Configuration.Abstractions

Getting started

The simplest use case is to bind up IConfigurationManager to System.Configuration.Abstractions.ConfigurationManager in your DI container. Alternatively, you can use System.Configuration.Abstractions.ConfigurationManager.Instance - a property that'll new up a new instance of IConfigurationManager each time it's accessed.

If you want to directly switch out calls to System.Configuration.ConfigurationManager in-place, to take advantage of the strongly typed extensions and IConfigurationInterceptors you can replace calls to System.Configuration.ConfigurationManager with calls to System.Configuration.Abstractions.ConfigurationManager.Instance in-line, and your code should function identically.

Lastly, you can just new up an instance of System.Configuration.Abstractions.ConfigurationManager anywhere, using its default constructor, and everything'll be just fine.

Examples:

    // Usages

    // You can use the singleton
    var valString = ConfigurationManager.Instance.AppSettings["stringKey"];
    var valInt = ConfigurationManager.Instance.AppSettings.AppSetting<int>("intKey");

    // You can new up an instance
    var configMgr = new ConfigurationManager();
    var valString2 = configMgr.AppSettings["stringKey"];
    var valInt2 = configMgr.AppSettings.AppSetting<int>("intKey");

    // You can new up an instance with configuration values
    var configMgr3 = new ConfigurationManager(new NameValueCollection {{"stringKey", "hello"}, {"intKey", "123"}});
    var valString3 = configMgr3.AppSettings["stringKey"];
    var valInt3 = configMgr3.AppSettings.AppSetting<int>("intKey");

    // You can just switch out calls in place for backwards compatible behaviour
    var old = System.Configuration.ConfigurationManager.AppSettings["stringKey"];
    var @new = ConfigurationManager.Instance.AppSettings["stringKey"];

    // You can wire up to your container
    ninjectContainer.Bind<IConfigurationManager>().ToMethod(()=> return new ConfigurationManager());

Features

Generic typed helper methods for retrieving typed config values

The IAppSettingsExtended interface, which our AppSettingsExtended class implements, contains four new methods:

  • string AppSetting(string key, Func<string> whenKeyNotFoundInsteadOfThrowingDefaultException = null);
  • T AppSetting<T>(string key, Func<T> whenKeyNotFoundInsteadOfThrowingDefaultException = null);
  • T AppSettingConvert<T>(string key, Func<T> whenConversionFailsInsteadOfThrowingDefaultException = null);
  • T AppSettingSilent<T>(string key, Func<T> insteadOfThrowingDefaultException = null);

These strongly typed "AppSetting" helpers, will convert any primitive types that Convert.ChangeType supports. The most obvious use case being int / bool / float / int? / bool? from their string representations - keeping alot of noisy conversions out of your code. You can also provide an optional Func which will get invoked if the key you're requesting is not found - otherwise, we'll throw an exception.

The following usage examples illustrate how to use these helpers:

    // Before *******************************

    var settingThatIsAnInteger = System.Configuration.ConfigurationManager.AppSettings["key"];
    int someInt;
    if (Int32.TryParse(settingThatIsAnInteger, out someInt))
    {
        someInt = 123; // Default
    }

    var settingThatIsABool = System.Configuration.ConfigurationManager.AppSettings["otherKey"];
    bool someBool;
    if (bool.TryParse(settingThatIsAnInteger, out someBool))
    {
        someBool = true; // Default
    }

	bool? someBool;
	try
	{
		var settingThatIsABool = System.Configuration.ConfigurationManager.AppSettings["otherKey"];
		if (bool.TryParse(settingThatIsAnInteger, out someBool))
		{
			someBool = true; // Default
		}
	}
	catch
	{
		someBool = true;
	}

    // After ********************************

    var withADefault = ConfigurationManager.Instance.AppSettings.AppSetting("key", () => 123);
    var withoutADefault = ConfigurationManager.Instance.AppSettings.AppSetting<int>("key");

    var worksWithAllPrimatives = ConfigurationManager.Instance.AppSettings.AppSetting<bool>("otherKey");
    var worksWithNullables = ConfigurationManager.Instance.AppSettings.AppSetting<bool?>("otherKey");

    var customNotFoundHandler = ConfigurationManager.Instance.AppSettings.AppSetting<bool?>("otherKey", () =>
    {
        throw new MyCustomMissingKeyException();
    });

    var customNotFoundHandler = ConfigurationManager.Instance.AppSettings.AppSetting<bool?>("otherKey", () =>
    {
        throw new MyCustomMissingKeyException();
    },
	() =>
    {
        throw new MyCustomConversionException();
    });

    var customNotFoundHandler = configurationManagerExtended.AppSettingConvert<bool?>("otherKey", () =>
    {
        throw new MyCustomConversionException();
    });

	var defaultValue = true;
	var silentHandler = configurationManagerExtended.AppSettingSilent<bool>("otherKey", () =>
    {
		// Log Warning
		// ...

		// Return Default
        return defaultValue;
    });

IConfigurationInterceptors

IConfigurationInterceptor's are hooks that, if registered, allow you to intercept and manipulate the values retrieved from configuration. IConnectionStringInterceptor's are hooks that allow you to manipulate connection strings during retrieval in a similar manner.

To wire up an IConfigurationInterceptor or IConnectionStringInterceptor, first, implement one, then call the static method ConfigurationManager.RegisterInterceptors(interceptor); Your interceptors are singletons and should be thread safe as the same instance could be called across multiple threads concurrently.

Example:

	ConfigurationManager.RegisterInterceptors(new ConfigurationSubstitutionInterceptor());
	var result = ConfigurationManager.Instance.AppSettings.AppSetting<string>("key"); // Interceptor executes
	var result2 = ConfigurationManager.Instance.AppSettings["key"]; // Interceptor executes

Interceptors fire for both the AppSetting helper, and the standard NameValueCollection methods and indexers. If you want to by-pass interception, access the "Raw" property for the original collection. This is a change in behaviour in V2.

Why would I want interceptors?

An obvious example would be the presence of an appSetting looking like this:

    <add key="my-key" value="{machineName}-something" />

You could easily add an interceptor to detect and fill in {machineName} from an environmental variable, keeping your configuration free of painful transformations. There are several other useful scenarios (auditing and logging, substitution, multi-tenancy) that interceptors could be useful in.

Included Interceptors

ConfigurationSubstitutionInterceptor

The ConfigurationSubstitutionInterceptor is bundled with the package, firstly as an example, but also as a useful configuration interceptor. It supports embedding any appsetting into any other. Given:

    <add key="key1" value="valueOfOne" />
    <add key="key2" value="{key1}-valueOfTwo" />

With this interceptor registered, this is true:

	var result = ConfigurationManager.AppSetting<string>("key2");
	Console.WriteLine(result); // writes: valueOfOne-valueOfTwo

This interceptor will help you simplify transformed web or app config files that rely on similar / repetitive token replacements, by allowing you to override just one value, and have it nested across the rest of your configuration using the interceptor.

ITypeConverters

Wired up just like IConfigurationInterceptors - TypeConverters let you specify custom type conversion logic. We include one TypeConverter by default - that converters to Uri. To implement your own type converter, you need to implement the following interface:

public interface IConvertType
{
	Type TargetType { get; }
	object Convert(string configurationValue);
}

and register your converter by using

var converter = new UserConverterExample();
ConfigurationManager.RegisterTypeConverters(converter);

Your type converter will then be invoked whenever you request a mapping to the type that your converter supports.

Contributing

Send a pull request with a passing test for any bugs or interesting extension ideas.

Credits

David Whitney

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].