ktsu.AppData 1.0.7-pre.1

Prefix Reserved
This is a prerelease version of ktsu.AppData.
dotnet add package ktsu.AppData --version 1.0.7-pre.1
                    
NuGet\Install-Package ktsu.AppData -Version 1.0.7-pre.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ktsu.AppData" Version="1.0.7-pre.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ktsu.AppData" Version="1.0.7-pre.1" />
                    
Directory.Packages.props
<PackageReference Include="ktsu.AppData" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ktsu.AppData --version 1.0.7-pre.1
                    
#r "nuget: ktsu.AppData, 1.0.7-pre.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=ktsu.AppData&version=1.0.7-pre.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ktsu.AppData&version=1.0.7-pre.1&prerelease
                    
Install as a Cake Tool

AppData

NuGet Build Status License: MIT

A modern, SOLID-compliant application data storage library for .NET that provides type-safe persistence with full dependency injection support.

โœจ Features

  • ๐Ÿ—๏ธ SOLID Architecture: Clean separation of concerns with dependency injection
  • ๐ŸŽฏ Type Safety: Strongly-typed paths using ktsu.Semantics
  • ๐Ÿ”ง Dependency Injection: Full DI support with standard .NET patterns
  • ๐Ÿงช Testable: Easy mocking and isolated unit testing
  • ๐Ÿ“ Backup & Recovery: Automatic backup and corruption recovery
  • โšก Performance: Debounced saves and efficient file operations
  • ๐Ÿ”’ Thread Safe: Safe for concurrent access
  • ๐Ÿ“ฆ Zero Dependencies: Minimal external dependencies

๐Ÿš€ Quick Start

Installation

dotnet add package ktsu.AppData

Basic Usage

  1. Configure services (Program.cs):
using ktsu.AppData.Configuration;

var services = new ServiceCollection();
services.AddAppData();
services.AddTransient<IMyService, MyService>();

using var serviceProvider = services.BuildServiceProvider();
  1. Create your data model:
using ktsu.AppData;

public class UserSettings : AppData<UserSettings>
{
    public string Theme { get; set; } = "Light";
    public string Language { get; set; } = "English";
    public Dictionary<string, string> Preferences { get; set; } = new();
}
  1. Use in your services:
using ktsu.AppData.Interfaces;

public class MyService
{
    private readonly IAppDataRepository<UserSettings> _repository;
    
    public MyService(IAppDataRepository<UserSettings> repository)
    {
        _repository = repository;
    }
    
    public void SaveUserPreferences(string theme, string language)
    {
        var settings = new UserSettings
        {
            Theme = theme,
            Language = language
        };
        
        settings.Save(_repository);
    }
    
    public UserSettings LoadUserPreferences()
    {
        return _repository.LoadOrCreate();
    }
}

๐Ÿ“– Usage Examples

ASP.NET Core Integration

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add AppData services
builder.Services.AddAppData(options =>
{
    // Custom JSON options
    options.JsonSerializerOptions = new JsonSerializerOptions
    {
        WriteIndented = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    };
});

// Add your services
builder.Services.AddScoped<IUserService, UserService>();

var app = builder.Build();

Custom File Locations

public class DatabaseConfig : AppData<DatabaseConfig>
{
    public string ConnectionString { get; set; } = "";
    public int TimeoutSeconds { get; set; } = 30;
    
    // Save to custom subdirectory
    protected override RelativeDirectoryPath? Subdirectory => 
        "database".As<RelativeDirectoryPath>();
    
    // Use custom filename
    protected override FileName? FileNameOverride => 
        "db_config.json".As<FileName>();
}

Queued Saves with Debouncing

public class RealTimeService
{
    private readonly IAppDataRepository<AppState> _repository;
    private readonly AppState _state = new();
    
    public RealTimeService(IAppDataRepository<AppState> repository)
    {
        _repository = repository;
    }
    
    public void UpdateState(string key, string value)
    {
        _state.Data[key] = value;
        _state.QueueSave(); // Queues save, doesn't write immediately
    }
    
    public async Task FlushChanges()
    {
        _state.SaveIfRequired(_repository); // Only saves if debounce time elapsed
    }
}

๐Ÿงช Testing

The library provides excellent testing support with mock file systems:

[Test]
public async Task UserService_SavesSettings_Successfully()
{
    // Arrange
    var services = new ServiceCollection();
    services.AddAppDataForTesting(() => new MockFileSystem());
    services.AddTransient<IUserService, UserService>();
    
    using var serviceProvider = services.BuildServiceProvider();
    var userService = serviceProvider.GetRequiredService<IUserService>();
    
    // Act
    userService.SaveUserPreferences("Dark", "Spanish");
    
    // Assert
    var settings = userService.LoadUserPreferences();
    Assert.AreEqual("Dark", settings.Theme);
    Assert.AreEqual("Spanish", settings.Language);
}

โš™๏ธ Configuration Options

Default Configuration

services.AddAppData();

Custom Serialization

services.AddAppData(options =>
{
    options.JsonSerializerOptions = new JsonSerializerOptions
    {
        WriteIndented = false,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };
});

Custom File System

services.AddAppData(options =>
{
    options.FileSystemFactory = _ => new MyCustomFileSystem();
});

Replace Components

services.AddAppData();

// Replace with custom implementations
services.Replace(ServiceDescriptor.Singleton<IAppDataSerializer, XmlSerializer>());
services.Replace(ServiceDescriptor.Singleton<IAppDataPathProvider, CustomPathProvider>());

๐Ÿ—๏ธ Architecture

The library follows SOLID principles with a clean, dependency-injection-based architecture:

graph TD
    A[AppData&lt;T&gt;<br/>Data Model] --> B[IAppDataRepository&lt;T&gt;<br/>Operations]
    B --> C[IAppDataFileManager<br/>File Operations]
    B --> D[IAppDataSerializer<br/>JSON Serialization]
    B --> E[IAppDataPathProvider<br/>Path Management]
    C --> E
    
    F[Your Service] --> B
    G[DI Container] --> B
    G --> C
    G --> D
    G --> E

Core Interfaces

  • IAppDataRepository<T>: High-level data operations (Load, Save)
  • IAppDataFileManager: File I/O with backup/recovery
  • IAppDataSerializer: Data serialization (JSON by default)
  • IAppDataPathProvider: Type-safe path management

๐Ÿ“ File Storage

Data is stored in the user's application data directory:

Windows: %APPDATA%\{ApplicationName}\
macOS:   ~/Library/Application Support/{ApplicationName}/
Linux:   ~/.config/{ApplicationName}/

Files are saved with automatic backup and recovery:

  • Primary file: user_settings.json
  • Backup file: user_settings.json.bk (temporary during writes)
  • Recovery: Automatic restoration from backup if primary file is corrupted

๐Ÿ”„ Migration Guide

From Version 1.x (Static API)

Old (v1.x):

public class Settings : AppData<Settings>
{
    public string Theme { get; set; }
}

// Static usage
var settings = Settings.Get();
settings.Theme = "Dark";
settings.Save();

New (v2.x):

public class Settings : AppData<Settings>
{
    public string Theme { get; set; }
}

// Dependency injection
public class MyService
{
    private readonly IAppDataRepository<Settings> _repository;
    
    public MyService(IAppDataRepository<Settings> repository)
    {
        _repository = repository;
    }
    
    public void UpdateTheme(string theme)
    {
        var settings = _repository.LoadOrCreate();
        settings.Theme = theme;
        settings.Save(_repository);
    }
}

๐ŸŽฏ Best Practices

1. Use Dependency Injection

Always inject IAppDataRepository<T> rather than using static methods:

โœ… Good:

public MyService(IAppDataRepository<Settings> repository)
{
    _repository = repository;
}

โŒ Avoid:

var repository = AppData.GetRepository<Settings>(); // Static access

2. Handle Disposal Properly

Save queued changes before disposal:

using var settings = new Settings();
settings.QueueSave();
settings.SaveIfRequired(repository); // Save before disposal

3. Use Custom Paths Appropriately

Override paths for logical grouping:

public class DatabaseSettings : AppData<DatabaseSettings>
{
    protected override RelativeDirectoryPath? Subdirectory => 
        "database".As<RelativeDirectoryPath>();
}

public class UiSettings : AppData<UiSettings>
{
    protected override RelativeDirectoryPath? Subdirectory => 
        "ui".As<RelativeDirectoryPath>();
}

4. Test with Mock File Systems

Always use AddAppDataForTesting() in unit tests:

services.AddAppDataForTesting(() => new MockFileSystem());

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
1.0.7-pre.1 109 6/18/2025
1.0.6 127 6/17/2025
1.0.5 126 6/17/2025

## v1.0.7-pre.1 (prerelease)

Changes since v1.0.6:

- Bump the ktsu group with 1 update ([@dependabot[bot]](https://github.com/dependabot[bot]))