ktsu.AppDataStorage 1.15.21
ktsu.AppDataStorage
A .NET library for simple, persistent application data management with JSON serialization.
Introduction
ktsu.AppDataStorage is a .NET library designed to simplify the process of persisting application data. It stores configuration or state data as JSON files in the user's application data folder, with built-in safety mechanisms like automatic backups, debounced saves, and thread-safe operations. The library provides a singleton-like access pattern and supports custom subdirectories and file names for organizing data.
Features
- Easy-to-use API: Inherit from
AppData<T>and get automatic JSON persistence withLoadOrCreate(),Save(), andGet(). - Automatic Backup: Creates backup files before overwriting to prevent data loss, with timestamped collision handling.
- Safe Write Pattern: Writes to a temporary file first, then atomically replaces the original to avoid corruption.
- Debounced Saves:
QueueSave()andSaveIfRequired()prevent frequent file writes with a 3-second debounce window. - Thread-Safe Operations: All file operations are synchronized with lock objects (uses
Locktype on .NET 9+,objecton earlier versions). - Singleton Access:
Get()provides lazy-initialized, singleton-like access to your app data instance. - Custom Storage Locations: Support for custom subdirectories and file names via
LoadOrCreate()overloads. - File System Abstraction: Uses
System.IO.Abstractionsfor easy unit testing with mock file systems. - Corrupt File Recovery: Automatically falls back to backup files when the main data file is corrupt or missing.
- Dispose-on-Exit: Registers for process exit to ensure queued saves are flushed before the application terminates.
Installation
Package Manager Console
Install-Package ktsu.AppDataStorage
.NET CLI
dotnet add package ktsu.AppDataStorage
Package Reference
<PackageReference Include="ktsu.AppDataStorage" Version="x.y.z" />
Usage Examples
Basic Example
Create a class that inherits from AppData<T>, where T is your custom data type.
using ktsu.AppDataStorage;
public class MySettings : AppData<MySettings>
{
public string Theme { get; set; } = "light";
public int FontSize { get; set; } = 14;
public bool AutoSave { get; set; } = true;
}
// Load existing data or create a new instance
var settings = MySettings.LoadOrCreate();
Console.WriteLine(settings.Theme); // "light"
Console.WriteLine(settings.FontSize); // 14
Accessing the Singleton Instance
The Get() method provides a lazy-initialized singleton instance, automatically calling LoadOrCreate() on first access.
using ktsu.AppDataStorage;
// Access the singleton from anywhere in your application
var settings = MySettings.Get();
settings.Theme = "dark";
settings.Save();
// Same instance returned every time
var sameSettings = MySettings.Get();
Console.WriteLine(sameSettings.Theme); // "dark"
Saving Data
Modify properties and call Save() to persist changes immediately.
using ktsu.AppDataStorage;
var settings = MySettings.Get();
settings.Theme = "dark";
settings.FontSize = 16;
settings.Save();
Custom Storage Location
Use overloads of LoadOrCreate() to store data in subdirectories or with custom file names.
using ktsu.AppDataStorage;
using ktsu.Semantics.Paths;
// Store in a subdirectory
var profileData = MySettings.LoadOrCreate(RelativeDirectoryPath.Create("profiles"));
// Store with a custom file name
var customData = MySettings.LoadOrCreate(FileName.Create("user_preferences.json"));
// Both subdirectory and custom file name
var specificData = MySettings.LoadOrCreate(
RelativeDirectoryPath.Create("profiles"),
FileName.Create("admin_settings.json"));
Advanced Usage
Queued and Debounced Saving
For scenarios with frequent updates (e.g., UI-driven changes), use QueueSave() to schedule a save that is debounced with a 3-second threshold. Call SaveIfRequired() periodically (e.g., in a game loop or timer) to flush queued saves.
using ktsu.AppDataStorage;
var settings = MySettings.Get();
settings.Theme = "dark";
settings.QueueSave(); // Schedules a save
// Later, in your update loop or timer:
settings.SaveIfRequired(); // Saves only if 3+ seconds have elapsed since QueueSave
// Or use the static convenience methods:
MySettings.QueueSave();
MySettings.SaveIfRequired();
Queued saves are also automatically flushed when the AppData<T> instance is disposed or when the process exits.
Testing with Mock File Systems
The library supports System.IO.Abstractions for testability. Configure a mock file system in your tests:
using System.IO.Abstractions.TestingHelpers;
using ktsu.AppDataStorage;
// In test setup - each thread gets its own isolated instance
AppData.ConfigureForTesting(() => new MockFileSystem());
// Run your tests...
var data = MySettings.LoadOrCreate();
data.Theme = "test";
data.Save();
// In test teardown
AppData.ResetFileSystem();
Directory and File Paths
Data is stored in a directory unique to the current application domain under the user's %APPDATA% folder. File names are derived from the class name in snake_case.
using ktsu.AppDataStorage;
// View the storage path
Console.WriteLine(AppData.Path);
// e.g., C:\Users\{user}\AppData\Roaming\{AppDomainName}
// File name is automatically generated from the class name
// MySettings -> my_settings.json
API Reference
AppData Static Class
Provides static helper methods and properties for managing application data storage.
Properties
| Name | Type | Description |
|---|---|---|
Path |
AbsoluteDirectoryPath |
The path where persistent data is stored for this application |
Methods
| Name | Return Type | Description |
|---|---|---|
WriteText<T>(T appData, string text) |
void |
Writes text to an app data file using a safe write pattern |
ReadText<T>(T appData) |
string |
Reads text from an app data file, falling back to backup if missing |
QueueSave<T>(this T appData) |
void |
Extension method that queues a debounced save operation |
SaveIfRequired<T>(this T appData) |
void |
Extension method that saves if the debounce threshold has elapsed |
ConfigureForTesting(Func<IFileSystem>) |
void |
Configures a mock file system factory for unit testing |
ResetFileSystem() |
void |
Resets the file system to the default implementation after testing |
AppData<T> Generic Abstract Class
Base class for app data storage. Inherit from this class to create persistable data types.
Type Constraints
T : AppData<T>, IDisposable, new()
Instance and Static Methods
| Name | Return Type | Description |
|---|---|---|
Get() |
T |
Gets the lazy-initialized singleton instance of the app data |
LoadOrCreate() |
T |
Loads app data from file or creates a new instance if none exists |
LoadOrCreate(RelativeDirectoryPath?) |
T |
Loads or creates with a custom subdirectory |
LoadOrCreate(FileName?) |
T |
Loads or creates with a custom file name |
LoadOrCreate(RelativeDirectoryPath?, FileName?) |
T |
Loads or creates with both custom subdirectory and file name |
Save() |
void |
Serializes and saves the app data to its JSON file |
QueueSave() |
void |
Queues a debounced save for the singleton instance |
SaveIfRequired() |
void |
Saves the singleton instance if the debounce threshold has elapsed |
Dispose() |
void |
Disposes the instance, flushing any queued saves |
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
License
This project is licensed under the MIT License. See the LICENSE.md file for details.
Showing the top 20 packages that depend on ktsu.AppDataStorage.
| Packages | Downloads |
|---|---|
|
ktsu.BlastMerge
Cross-repository file synchronization tool that uses intelligent iterative merging to unify multiple file versions with interactive conflict resolution. Features include batch processing with custom search paths and exclusion patterns, parallel file hashing for performance, persistent command history, and comprehensive automation capabilities for multi-repository workflows. Supports advanced diff visualization, pattern-based file discovery, and discrete processing phases with real-time progress reporting.
|
181 |
|
ktsu.BlastMerge
Cross-repository file synchronization tool that uses intelligent iterative merging to unify multiple file versions with interactive conflict resolution. Features include batch processing with custom search paths and exclusion patterns, parallel file hashing for performance, persistent command history, and comprehensive automation capabilities for multi-repository workflows. Supports advanced diff visualization, pattern-based file discovery, and discrete processing phases with real-time progress reporting.
|
171 |
|
ktsu.BlastMerge
Cross-repository file synchronization tool that uses intelligent iterative merging to unify multiple file versions with interactive conflict resolution. Features include batch processing with custom search paths and exclusion patterns, parallel file hashing for performance, persistent command history, and comprehensive automation capabilities for multi-repository workflows. Supports advanced diff visualization, pattern-based file discovery, and discrete processing phases with real-time progress reporting.
|
170 |
|
ktsu.BlastMerge
Cross-repository file synchronization tool that uses intelligent iterative merging to unify multiple file versions with interactive conflict resolution. Features include batch processing with custom search paths and exclusion patterns, parallel file hashing for performance, persistent command history, and comprehensive automation capabilities for multi-repository workflows. Supports advanced diff visualization, pattern-based file discovery, and discrete processing phases with real-time progress reporting.
|
169 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
144 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
139 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
137 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
136 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
87 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
74 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
61 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
60 |
|
ktsu.SingleAppInstance
A .NET library that ensures only one instance of your application is running at a time.
|
59 |
.NET 7.0
- Polyfill (>= 9.9.0)
- TestableIO.System.IO.Abstractions (>= 22.1.0)
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
- ktsu.CaseConverter (>= 1.3.12)
- ktsu.RoundTripStringJsonConverter (>= 1.0.10)
- ktsu.Semantics.Paths (>= 1.0.31)
.NET 10.0
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
- ktsu.RoundTripStringJsonConverter (>= 1.0.10)
- ktsu.Semantics.Paths (>= 1.0.31)
- TestableIO.System.IO.Abstractions (>= 22.1.0)
- Polyfill (>= 9.9.0)
- ktsu.CaseConverter (>= 1.3.12)
.NET Standard 2.0
- Polyfill (>= 9.9.0)
- TestableIO.System.IO.Abstractions (>= 22.1.0)
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
- ktsu.CaseConverter (>= 1.3.12)
- ktsu.RoundTripStringJsonConverter (>= 1.0.10)
- ktsu.Semantics.Paths (>= 1.0.31)
.NET Standard 2.1
- Polyfill (>= 9.9.0)
- TestableIO.System.IO.Abstractions (>= 22.1.0)
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
- ktsu.CaseConverter (>= 1.3.12)
- ktsu.RoundTripStringJsonConverter (>= 1.0.10)
- ktsu.Semantics.Paths (>= 1.0.31)
.NET 9.0
- ktsu.RoundTripStringJsonConverter (>= 1.0.10)
- ktsu.Semantics.Paths (>= 1.0.31)
- Polyfill (>= 9.9.0)
- TestableIO.System.IO.Abstractions (>= 22.1.0)
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
- ktsu.CaseConverter (>= 1.3.12)
.NET 8.0
- TestableIO.System.IO.Abstractions (>= 22.1.0)
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
- Polyfill (>= 9.9.0)
- ktsu.RoundTripStringJsonConverter (>= 1.0.10)
- ktsu.Semantics.Paths (>= 1.0.31)
- ktsu.CaseConverter (>= 1.3.12)
| Version | Downloads | Last updated |
|---|---|---|
| 1.16.1 | 45 | 02/23/2026 |
| 1.16.0 | 53 | 02/19/2026 |
| 1.15.21 | 55 | 02/19/2026 |
| 1.15.20 | 56 | 02/18/2026 |
| 1.15.19 | 55 | 02/17/2026 |
| 1.15.18 | 57 | 02/16/2026 |
| 1.15.17 | 54 | 02/16/2026 |
| 1.15.17-pre.1 | 57 | 02/16/2026 |
| 1.15.16 | 56 | 02/14/2026 |
| 1.15.15 | 55 | 02/14/2026 |
| 1.15.14 | 63 | 02/06/2026 |
| 1.15.14-pre.11 | 58 | 02/06/2026 |
| 1.15.14-pre.10 | 60 | 02/05/2026 |
| 1.15.14-pre.9 | 59 | 02/04/2026 |
| 1.15.14-pre.8 | 63 | 02/03/2026 |
| 1.15.14-pre.7 | 60 | 02/03/2026 |
| 1.15.14-pre.6 | 60 | 02/02/2026 |
| 1.15.14-pre.5 | 58 | 02/01/2026 |
| 1.15.14-pre.4 | 58 | 01/31/2026 |
| 1.15.14-pre.3 | 61 | 01/31/2026 |
| 1.15.14-pre.2 | 63 | 01/31/2026 |
| 1.15.14-pre.1 | 60 | 01/30/2026 |
| 1.15.13 | 64 | 01/30/2026 |
| 1.15.13-pre.10 | 61 | 01/29/2026 |
| 1.15.13-pre.9 | 62 | 01/28/2026 |
| 1.15.13-pre.8 | 63 | 01/28/2026 |
| 1.15.13-pre.7 | 66 | 01/26/2026 |
| 1.15.13-pre.6 | 64 | 01/26/2026 |
| 1.15.13-pre.5 | 62 | 01/25/2026 |
| 1.15.13-pre.4 | 64 | 01/24/2026 |
| 1.15.13-pre.3 | 67 | 01/22/2026 |
| 1.15.13-pre.2 | 66 | 01/21/2026 |
| 1.15.13-pre.1 | 66 | 01/19/2026 |
| 1.15.12 | 67 | 01/19/2026 |
| 1.15.12-pre.1 | 83 | 01/12/2026 |
| 1.15.11 | 106 | 01/08/2026 |
| 1.15.11-pre.4 | 100 | 01/08/2026 |
| 1.15.11-pre.3 | 153 | 11/24/2025 |
| 1.15.11-pre.2 | 158 | 11/23/2025 |
| 1.15.11-pre.1 | 148 | 11/23/2025 |
| 1.15.9 | 155 | 09/11/2025 |
| 1.15.8 | 159 | 08/25/2025 |
| 1.15.8-pre.2 | 151 | 08/25/2025 |