rskibbe.Settings – An abstration for settings
A lightweight, dependency-free settings abstraction for .NET
Please keep in mind that this is still a work in progress and that I’m doing this work for free, in my free time.
📖 Table of Contents
- Sub packages / Providers
- Getting started
- Problem
- Solution
- Thoughts & Concept
- Why use an abstraction?
- My personal goal / story
- Roadmap
🧩 Sub packages / providers
After installing the base / contract package rskibbe.Settings you need to get an actual provider, like rskibbe.Settings.Ini, Json, etc.
Here’s a list of supported sub packages / providers:
- [x] rskibbe.Settings.Ini
- [ ] rskibbe.Settings.Json
- [ ] rskibbe.Settings.Csv
- [ ] rskibbe.Settings.Xml
- [ ] rskibbe.Settings.Db
- [ ] rskibbe.Settings.Http
▶️ Getting started
You can get started by installing the base-package first, followed by the sub / provider package.
Install the base package
This package is the essence where your things depend on mainly.
Install-Package rskibbe.Settings
Installl the provider package
You need something to provide the settings for you. Depending on your serialization / store of choice, you can for example use the Ini based sub package.
Usage
C#
// create an instance based on file path and register it in DI container if used
// A - using the file path only
var settingsService = new IniSettingsService(".\\settings.ini");
// B - using an existing IniFile instance
var iniFile = new IniFile(".\\settings.ini", Encoding.UTF8, Environment.NewLine);
var settingsService = new IniSettingsService(iniFile);
// get the service later on in your app
// maybe inside like Form1_Load, etc. (from DI container if used)
// load the settings
await settingsService.LoadSettingsAsync();
// somewhere, where you need settings, get them (async or sync - depending on need and implementation)
var value = await settingsService.GetValueAsync("SomeIniSection.SomeIniKey", "defaultValue");
// somewhere later like in Form1_Closing - persist the changes
await settingsService.PersistSettingsAsync();
VB.NET
' create an instance based on file path and register it in DI container if used
' A - using the file path only
Dim settingsService = New IniSettingsService(".\settings.ini")
' B - using an existing IniFile instance
Dim iniFile = New IniFile(".\settings.ini", Encoding.UTF8, Environment.NewLine)
Dim settingsService = New IniSettingsService(iniFile)
' get the service later on in your app
' maybe inside like Form1_Load, etc. (from DI container if used)
' load the settings
Await settingsService.LoadSettingsAsync()
' somewhere, where you need settings, get them (async or sync - depending on need and implementation)
Dim value = Await settingsService.GetValueAsync("SomeIniSection.SomeIniKey", "defaultValue")
' somewhere later like in Form1_Closing - persist the changes
Await settingsService.PersistSettingsAsync()
⚠️ Problem
In many .NET applications, configuration is accessed directly from INI files, static APIs, etc. – especially in legacy applications.
This tightly couples your application logic to a specific configuration format and makes future changes, testing and reuse unnecessarily hard.
The red path shows the usual problem:
A tightly coupled call to the implementation, for example being an Ini based configuration.
The green path shows the cleaner way:
Your app doesn’t pretty much know / care how the values are retrieved in detail (a call to „Ini“ in each file…). It just communicates the need of a configuration information based on the contract – for example – of the GetValue function of the ISettingsReader interface.

✅️ Solution
rskibbe.Settings introduces a simple abstraction for application settings.
Your code depends on an interface – not on INI files, databases or config formats.
Install an already completed sub-package or create your own implementation if it doesn’t exist, yet.
🧠 Thoughts & Concept
When creating a solution we need to watch out for some pitfalls that we could be facing.
There are many different ways of creating something „simple“ like settings – making it not so easy anymore, if done good.
As my time is just as limited as yours, I will try my best to think about stuff, but – you know…
You will find the things I’ll care about before the horizonal line, and other – left out (?) thoughts – below it.
App / Settings Flow
You can see an image of my example app flow here.

General Separation of Concerns
Saying „every bird can fly“ breaks the moment you meet an emu. Same idea here: I don’t want a settings interface that implies values are always writable.
Some sources – like environment variables – are effectively read-only.
Reading isn’t the same as „loading“ and writing isn’t the same as „persisting“.
This is why I divided the responsibilities into some interfaces.

There might be some more stuff later, I’ll see as my time allows – but you get the key.
Sync / Async:
We might want to store our settings inside a database or even using a web API. So it would be pretty bad, if I’d force the consumers of my settings stuff to always use synchronous methods & implementations.
It’s not always Read & Write
Reading and writing is fine, but what if our underlying implementation doesn’t support setting / writing values? Like when we’re using environment variables – for example.
Writing doesn’t mean persisting
A common misunderstanding, or rather, something I have often observed among my clients. They confuse writing with persisting values. Not every setting of a value should trigger an actual persist.
Reading / Writing multiple values
When reading / writing our values, we should think about batching stuff together. Why would I – for example – send 3 requests to get 3 settings, if I could just combine them into one call?
Versioning of settings
You might have different versions of your files, that need to be handled individually.
Logging / Tracing
Who changed what and etc.
Access Control
Who has access to what
Encryption
Some things shouldn’t be seen clearly.
Health Check
Is my provider available?
Import / Export
Watcher / Notifications
FileSystemWatcher / DB-polling / …
Caching
Concurrency
🤔 Why use an abstraction?
- Change the configuration source without touching business logic
- Enable unit testing without real configuration files
- Makes usage easy, no chaos
- Reduce coupling in codebases
🏁 My personal goal / story
As a freelance developer facing these kinds of „problems“ everyday (hard to maintain, non-flexible, „bad“ code), I finally wanted to centralize this stuff a bit so I can re-use it myself considering my customers and potential clients.
So, feel free to use it, or not 🙆♂️…
🧭 Roadmap
- More providers
Abstraction is not about complexity.
It’s about keeping options open.