Configuration.Writable.Encrypt
0.1.0-alpha.18
See the version list below for details.
dotnet add package Configuration.Writable.Encrypt --version 0.1.0-alpha.18
NuGet\Install-Package Configuration.Writable.Encrypt -Version 0.1.0-alpha.18
<PackageReference Include="Configuration.Writable.Encrypt" Version="0.1.0-alpha.18" />
<PackageVersion Include="Configuration.Writable.Encrypt" Version="0.1.0-alpha.18" />
<PackageReference Include="Configuration.Writable.Encrypt" />
paket add Configuration.Writable.Encrypt --version 0.1.0-alpha.18
#r "nuget: Configuration.Writable.Encrypt, 0.1.0-alpha.18"
#:package Configuration.Writable.Encrypt@0.1.0-alpha.18
#addin nuget:?package=Configuration.Writable.Encrypt&version=0.1.0-alpha.18&prerelease
#tool nuget:?package=Configuration.Writable.Encrypt&version=0.1.0-alpha.18&prerelease
Configuration.Writable
A lightweight library that extends Microsoft.Extensions.Configuration to easily handle user settings.
Features
- Read and write user settings with type safety.
- Extends
Microsoft.Extensions.Configurationand integrates seamlessly withIHostApplication. - Simple API that can be easily used in applications both with and without DI.
- Supports various file formats (Json, Xml, Yaml, Encrypted, etc...) via providers.
Usage
Setup
Install Configuration.Writable from NuGet.
dotnet add package Configuration.Writable
Then, prepare a class (UserSetting) that you want to read and write as settings in advance.
public class UserSetting
{
public string Name { get; set; } = "default name";
public int Age { get; set; } = 20;
}
Without DI (Console, WinForms, WPF, etc.)
Use WritableConfig as the starting point for reading and writing settings.
using Configuration.Writable;
// initialize at once (application startup)
WritableConfig.Initialize<SampleSetting>();
// -------------
// get the writable config instance with the specified setting class
var options = WritableConfig.GetInstance<SampleSetting>();
// get the config instance
var sampleSetting = options.CurrentValue;
Console.WriteLine($">> Name: {sampleSetting.Name}");
// and save to storage
await options.SaveAsync(setting =>
{
setting.Name = "new name";
});
// By default, it's saved to ./usersettings.json
With DI (ASP.NET Core, Blazor, Worker Service, etc.)
First, call builder.AddUserConfigurationFile to register the settings.
// Program.cs
builder.AddUserConfigurationFile<UserSetting>();
// If you're not using IHostApplication, do the following:
var configuration = new ConfigurationManager();
services.AddUserConfigurationFile<UserSetting>(configuration);
Then, obtain and use IReadonlyOptions<T> or IWritableOptions<T> from the DI container as follows:
// read config in your class
// you can also use IOptions<T>, IOptionsMonitor<T> or IOptionsSnapshot<T>
public class ConfigReadService(IReadonlyOptions<UserSetting> config)
{
public void Print()
{
// get the config instance
var sampleSetting = config.CurrentValue;
Console.WriteLine($">> Name: {sampleSetting.Name}");
}
}
// read and write config in your class
public class ConfigReadWriteService(IWritableOptions<UserSetting> config)
{
public async Task UpdateAsync()
{
// get the config instance
var sampleSetting = config.CurrentValue;
// and save to storage
await config.SaveAsync(setting =>
{
setting.Name = "new name";
});
}
}
Customization
Configuration Method
You can change various settings as arguments to Initialize or AddUserConfigurationFile.
// Without DI
var options = WritableConfig.GetInstance<UserSetting>();
options.Initialize(opt => { /* ... */ });
// With DI
builder.AddUserConfigurationFile<UserSetting>(opt => { /* ... */ });
Save Location
Default behavior save to ./usersettings.json.
If you want to change the save location, use opt.FileName or opt.UseStandardSaveLocation("MyAppId").
For example:
// to save to the parent directory
opt.FileName = "../myconfig";
// to save to child directory
opt.FileName = "config/myconfig";
// to save to a common settings directory
opt.UseStandardSaveLocation("MyAppId");
Provider
If you want to change the format when saving files, create a class that implements IWritableConfigProvider and specify it in opt.Provider.
Currently, the following providers are available:
| Provider | Description | NuGet Package |
|---|---|---|
| WritableConfigJsonProvider | save in JSON format. | Built-in |
| WritableConfigXmlProvider | save in XML format. | |
| WritableConfigYamlProvider | save in YAML format. | |
| WritableConfigEncryptProvider | save in AES-256-CBC encrypted JSON format. |
// use Json format with indentation
opt.Provider = new WritableConfigJsonProvider() {
JsonSerializerOptions = { WriteIndented = true },
};
// use Yaml format
// (you need to install Configuration.Writable.Yaml package)
opt.Provider = new WritableConfigYamlProvider();
// use encrypted Json format
// (you need to install Configuration.Writable.Encrypt package)
opt.Provider = new WritableConfigEncryptProvider("any-encrypt-password");
FileWriter
If you want to change the way files are written, create a class that implements IFileWriter and specify it in opt.FileWriter.
For example, if you want to keep backup files when saving, use CommonFileWriter with BackupMaxCount > 0.
// keep 5 backup files when saving
opt.FileWriter = new CommonFileWriter() { BackupMaxCount = 5 };
SectionName
In default, the entire settings are saved in the following structure:
{
// settings saved to under "UserSettings" section
"UserSettings": {
"Name": "custom name",
"Age": 30
}
}
As you can see, the settings are written under the “UserSettings” section.
This serves as a guardrail to prevent conflicts with settings from other libraries (such as ASP.NET Core).
You can freely change this section name.
// change the section name to "MyAppSettings"
opt.SectionName = "MyAppSettings";
// nothing use section (written at the root, not recommended)
opt.SectionName = "";
InstanceName
If you want to manage multiple settings of the same type, you must specify different InstanceName for each setting.
// first setting
builder.AddUserConfigurationFile<UserSetting>(opt => {
opt.FileName = "firstsettings.json";
opt.InstanceName = "First";
// save section will be "UserSettings-First"
});
// second setting
builder.AddUserConfigurationFile<UserSetting>(opt => {
opt.FileName = "secondsettings.json";
opt.InstanceName = "Second";
// save section will be "UserSettings-Second"
});
// and get each setting from DI
public class MyService(IWritableOptions<UserSetting> config)
{
public void GetAndSave()
{
// cannot use .CurrentValue if multiple settings of the same type are registered
var firstSetting = config.Get("First");
var secondSetting = config.Get("Second");
// and you can must specify instance name when saving
await config.SaveAsync("First", setting => {
setting.Name = "first name";
});
await config.SaveAsync("Second", setting => {
setting.Name = "second name";
});
}
}
It is recommended to avoid managing multiple settings of the same type as much as possible and to create a single class that wraps them.
// recommended
public class AllSettings
{
public UserSetting First { get; set; } = new UserSetting();
public UserSetting Second { get; set; } = new UserSetting();
}
Merge multiple settings
TODO.
Testing
You can use InMemoryFileWriter to test reading and writing settings without touching the file system.
// setup
var sampleFileName = Path.GetRandomFileName();
var _fileWriter = new InMemoryFileWriter();
WritableConfig.Initialize<UserSetting>(opt => {
opt.FileName = sampleFileName;
opt.UseInMemoryFileWriter(_fileWriter);
});
var option = WritableConfig.GetInstance<UserSetting>();
// and your test execution
await options.SaveAsync(setting => {
setting.Name = "test name";
setting.Age = 99;
});
// check the saved content
Assert.True(_fileWriter.FileExists(sampleFileName));
var savedText = _fileWriter.ReadAllText(sampleFileName);
Assert.Contains("test name", savedText);
Why This Library?
There are many ways to handle user settings in C# applications. However, each has some drawbacks, and no de facto standard exists.
Using app.config (Settings.settings)
This is an old-fashioned approach that yields many search results (unfortunately!). When you start using it, you'll likely encounter the following issues:
- You need to manually write XML-based configuration files (or use Visual Studio's cumbersome GUI)
- It lacks type safety and is unsuitable for complex settings
- Files may be included in distributions without careful consideration, risking settings reset during updates
Reading and Writing Configuration Files Yourself
When considering type safety, the first approach that comes to mind is creating and reading/writing your own configuration files.
This method isn't bad, but the drawback is that there are too many things to consider.
- You need to write configuration management code yourself
- You need to implement many features like backup creation, settings merging, and update handling
- Integrating multiple configuration sources requires extra effort
- You need to implement configuration change reflection yourself
Using (Any Configuration Library)
Since there's so much boilerplate code, there must be some configuration library available.
Indeed, just searching for Config on NuGet yields many libraries.
I examined the major ones among these, but couldn't adopt them for the following reasons:
- DotNetConfig
- The file format uses a proprietary format (
.netconfig) - It appears to be primarily designed for
dotnet tools
- The file format uses a proprietary format (
- Config.Net
- It supports various providers but uses a unique storage format
- Collection writing is not supported in the JSON provider
Using Microsoft.Extensions.Configuration
Considering these current situations, Microsoft.Extensions.Configuration (MS.E.C) can be said to be the most standardized configuration management method in modern times.
It provides many features such as multi-file integration, support for various formats including environment variables, and configuration change reflection, and integrates seamlessly with IHostApplication.
However, since it's primarily designed for application settings, it's insufficient for handling user settings. The major problem is that configuration writing is not supported.
Another issue is that it's based on DI, making it somewhat cumbersome to use in console applications.
Apps that want to use configuration files are more likely to not use DI (examples include WinForms, WPF, console apps, etc.).
Configuration.Writable
The preamble has gotten long, but it's time for promotion!
This library extends Microsoft.Extensions.Configuration to make writing user settings easy.
It's also designed to be easily usable in applications that don't use DI.
Please give it a try. It's simple!
License
This project is licensed under the Apache-2.0 License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Configuration.Writable (>= 0.1.0-alpha.18)
-
net8.0
- Configuration.Writable (>= 0.1.0-alpha.18)
-
net9.0
- Configuration.Writable (>= 0.1.0-alpha.18)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 0.1.12 | 202 | 1/2/2026 | |
| 0.1.3 | 245 | 12/23/2025 | |
| 0.1.0 | 225 | 12/21/2025 | |
| 0.1.0-alpha.159 | 236 | 12/19/2025 | |
| 0.1.0-alpha.149 | 290 | 12/18/2025 | |
| 0.1.0-alpha.119 | 197 | 10/22/2025 | |
| 0.1.0-alpha.106 | 189 | 10/14/2025 | |
| 0.1.0-alpha.101 | 193 | 10/13/2025 | |
| 0.1.0-alpha.100 | 191 | 10/12/2025 | |
| 0.1.0-alpha.53 | 189 | 10/8/2025 | |
| 0.1.0-alpha.46 | 194 | 9/29/2025 | |
| 0.1.0-alpha.40 | 124 | 9/28/2025 | |
| 0.1.0-alpha.18 | 186 | 9/24/2025 | |
| 0.1.0-alpha.2 | 177 | 12/21/2025 | |
| 0.1.0-alpha.1 | 203 | 9/23/2025 |