v0.2.2 Changelog
Release date: February 27, 2026
v0.2.2 is a feature release in the v0.2.x line, containing one breaking change (plugin directory rename) and one new feature (plugin-specific data directory support).
Breaking Changes
Plugin directory renamed: Plugins/ → plugins/
The directory scanned by the host for plugin DLLs has been renamed from Plugins to plugins (lowercase initial letter) to follow cross-platform naming conventions.
| Environment | Impact |
|---|---|
| Linux / macOS | ⚠️ Affected: you must manually rename the existing Plugins/ directory to plugins/, otherwise all plugins will fail to load after the upgrade |
| Windows | ✅ Not affected: the file system is case-insensitive, no action required |
For step-by-step migration instructions, see the User-side Migration Guide.
New Features
New: Plugin-specific Data Directory (DataDirectory and GetDataPath)
Plugins can now access a dedicated data directory through two new interface members, suitable for storing databases, key pairs, caches, exported files, and other persistent data.
DataDirectory Property
Returns the full path to the plugin's dedicated data directory. Defaults to {BaseDir}/data/{PluginName}/.
// Default implementation
string DataDirectory => Path.Combine(AppContext.BaseDirectory, "data", Name);TIP
DataDirectory is intended to be used as a read-only property and should not be overridden. For a standardized and predictable plugin ecosystem, all persistent files produced by a plugin should always reside within the plugin's dedicated data directory.
GetDataPath(string relativePath) Method
A path-combining helper for DataDirectory, supporting both relative and absolute paths:
// Relative path → {DataDirectory}/keys/private.pem
var keyPath = GetDataPath("keys/private.pem");
// Absolute path → returned as-is; DataDirectory is ignored
var keyPath = GetDataPath("/mnt/hsm/private.pem");The absolute path passthrough behavior follows the native rules of
Path.Combine. This allows users to configure an absolute path in the plugin's config file to redirect storage to any location outside the data directory (e.g., an HSM mount point).
Automatic Directory Creation
The host automatically ensures the directory pointed to by DataDirectory exists before plugin services are registered. Plugins do not need to call Directory.CreateDirectory manually.
Example directory structure after startup:
{BaseDir}/
├── config/
│ └── my.plugin.json
└── data/
└── my.plugin/ ← created automatically by the host
├── plugin.db
└── keys/
└── private.pemUsage With Plugin Configuration
The recommended pattern is to set path fields to relative path strings in DefaultConfig. The host writes them to the config file on first run. In RegisterServices, use GetDataPath to resolve them to absolute paths at runtime. All persistent files produced by a plugin should always reside within the plugin's dedicated data directory.
public object? DefaultConfig => new MySettings
{
// ✅ Recommended: store relative paths in DefaultConfig
PrivateKeyPath = "keys/private.pem",
DatabasePath = "data.db"
};
public void RegisterServices(IServiceCollection services, IConfiguration configuration)
{
var settings = configuration.Get<MySettings>()!;
// GetDataPath resolves the relative path to an absolute path:
// "data.db" → {DataDirectory}/data.db
// "keys/private.pem" → {DataDirectory}/keys/private.pem
var resolvedKeyPath = GetDataPath(settings.PrivateKeyPath);
if (!File.Exists(resolvedKeyPath))
GenerateKeyPair(resolvedKeyPath);
services.Configure<MySettings>(configuration);
}Compatibility
- Both new members have default implementations — existing plugins require no code changes and will compile as-is
- NuGet references using
Version="0.2.*"will automatically resolve to this version - The host must be updated to v0.2.2 to gain automatic data directory creation; updating only the contracts library has no effect on existing behavior