https://github.com/ktsu-dev/appdata
https://github.com/ktsu-dev/appdata
Last synced: 8 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/ktsu-dev/appdata
- Owner: ktsu-dev
- License: mit
- Created: 2025-06-10T08:02:46.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2025-06-18T23:05:36.000Z (12 months ago)
- Last Synced: 2025-06-19T00:19:12.279Z (12 months ago)
- Language: PowerShell
- Size: 2.11 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
- Authors: AUTHORS.md
Awesome Lists containing this project
README
# AppData
[](https://www.nuget.org/packages/ktsu.AppData/)
[](https://github.com/ktsu-dev/AppData/actions)
[](https://opensource.org/licenses/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
```bash
dotnet add package ktsu.AppData
```
### Basic Usage
1. **Configure services** (Program.cs):
```csharp
using ktsu.AppData.Configuration;
var services = new ServiceCollection();
services.AddAppData();
services.AddTransient();
using var serviceProvider = services.BuildServiceProvider();
```
2. **Create your data model**:
```csharp
using ktsu.AppData;
public class UserSettings : AppData
{
public string Theme { get; set; } = "Light";
public string Language { get; set; } = "English";
public Dictionary Preferences { get; set; } = new();
}
```
3. **Use in your services**:
```csharp
using ktsu.AppData.Interfaces;
public class MyService
{
private readonly IAppDataRepository _repository;
public MyService(IAppDataRepository 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
```csharp
// 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();
var app = builder.Build();
```
### Custom File Locations
```csharp
public class DatabaseConfig : AppData
{
public string ConnectionString { get; set; } = "";
public int TimeoutSeconds { get; set; } = 30;
// Save to custom subdirectory
protected override RelativeDirectoryPath? Subdirectory =>
"database".As();
// Use custom filename
protected override FileName? FileNameOverride =>
"db_config.json".As();
}
```
### Queued Saves with Debouncing
```csharp
public class RealTimeService
{
private readonly IAppDataRepository _repository;
private readonly AppState _state = new();
public RealTimeService(IAppDataRepository 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:
```csharp
[Test]
public async Task UserService_SavesSettings_Successfully()
{
// Arrange
var services = new ServiceCollection();
services.AddAppDataForTesting(() => new MockFileSystem());
services.AddTransient();
using var serviceProvider = services.BuildServiceProvider();
var userService = serviceProvider.GetRequiredService();
// Act
userService.SaveUserPreferences("Dark", "Spanish");
// Assert
var settings = userService.LoadUserPreferences();
Assert.AreEqual("Dark", settings.Theme);
Assert.AreEqual("Spanish", settings.Language);
}
```
## โ๏ธ Configuration Options
### Default Configuration
```csharp
services.AddAppData();
```
### Custom Serialization
```csharp
services.AddAppData(options =>
{
options.JsonSerializerOptions = new JsonSerializerOptions
{
WriteIndented = false,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
});
```
### Custom File System
```csharp
services.AddAppData(options =>
{
options.FileSystemFactory = _ => new MyCustomFileSystem();
});
```
### Replace Components
```csharp
services.AddAppData();
// Replace with custom implementations
services.Replace(ServiceDescriptor.Singleton());
services.Replace(ServiceDescriptor.Singleton());
```
## ๐๏ธ Architecture
The library follows SOLID principles with a clean, dependency-injection-based architecture:
```mermaid
graph TD
A[AppData<T>
Data Model] --> B[IAppDataRepository<T>
Operations]
B --> C[IAppDataFileManager
File Operations]
B --> D[IAppDataSerializer
JSON Serialization]
B --> E[IAppDataPathProvider
Path Management]
C --> E
F[Your Service] --> B
G[DI Container] --> B
G --> C
G --> D
G --> E
```
### Core Interfaces
- **`IAppDataRepository`**: 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)**:
```csharp
public class Settings : AppData
{
public string Theme { get; set; }
}
// Static usage
var settings = Settings.Get();
settings.Theme = "Dark";
settings.Save();
```
**New (v2.x)**:
```csharp
public class Settings : AppData
{
public string Theme { get; set; }
}
// Dependency injection
public class MyService
{
private readonly IAppDataRepository _repository;
public MyService(IAppDataRepository 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` rather than using static methods:
โ
**Good**:
```csharp
public MyService(IAppDataRepository repository)
{
_repository = repository;
}
```
โ **Avoid**:
```csharp
var repository = AppData.GetRepository(); // Static access
```
### 2. Handle Disposal Properly
Save queued changes before disposal:
```csharp
using var settings = new Settings();
settings.QueueSave();
settings.SaveIfRequired(repository); // Save before disposal
```
### 3. Use Custom Paths Appropriately
Override paths for logical grouping:
```csharp
public class DatabaseSettings : AppData
{
protected override RelativeDirectoryPath? Subdirectory =>
"database".As();
}
public class UiSettings : AppData
{
protected override RelativeDirectoryPath? Subdirectory =>
"ui".As();
}
```
### 4. Test with Mock File Systems
Always use `AddAppDataForTesting()` in unit tests:
```csharp
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](LICENSE.md) file for details.
## ๐ Related Packages
- [`ktsu.Semantics`](https://github.com/ktsu-dev/Semantics) - Type-safe semantic types
- [`ktsu.CaseConverter`](https://github.com/ktsu-dev/CaseConverter) - String case conversion utilities
- [`ktsu.ToStringJsonConverter`](https://github.com/ktsu-dev/ToStringJsonConverter) - Custom JSON converters