Skip to main content
net10.0

Storage core for Koan: contracts, orchestrator, routing, and options.

Published
Jun 12, 2026
4mo ago
Total Downloads
5.1K
5,117

Install

dotnet add package Sylin.Koan.Storage --version 0.17.0
ProductVersions
.NET
net10.0

README

Koan.Storage

Storage orchestrator for Koan apps. Simple, profile-based routing with first-class DX to create, read, probe, copy, move, and delete objects across providers.

What it does

  • Routing: Resolves profile → provider+container using options or rules with safe defaults.
  • Orchestration: Streams data and computes SHA-256 for seekable uploads; supports range reads.
  • Capabilities: Leverages provider features like server-side copy; presign when available.
  • DX: Small, async helpers without Async suffix and a model-centric API for clean calls.

Setup

  • Registration: Packages auto-register via the framework pipeline. Call AppBootstrapper.InitializeModules(services) once. Providers (e.g., Local) self-register.
  • Core options:
    • Koan:Storage:Profiles:<name> → { Provider, Container }
    • Koan:Storage:DefaultProfile → string (optional)
    • Koan:Storage:FallbackMode → Disabled | SingleProfileOnly | NamedDefault (default SingleProfileOnly)
    • Koan:Storage:ValidateOnStart → bool (default true)

Notes

  • Ambient DI: APIs resolve IStorageService from AppHost.Current. In app host, this is set during startup (built into Koan templates).

Model‑centric API (recommended)

Bind a model type to a profile (and optionally a default container) and use concise statics/instance ops.

// Bind to profile "hot" (container optional; provider+container resolve via options)
[Koan.Storage.Infrastructure.StorageBinding("hot")] 
public sealed class FileA : Koan.Storage.Model.StorageEntity<FileA> { }

[Koan.Storage.Infrastructure.StorageBinding("cold")] 
public sealed class FileB : Koan.Storage.Model.StorageEntity<FileB> { }

// Create → Read → Copy/Move
var rec = await FileA.CreateTextFile("name.txt", "hello");
var text = await FileA.Get(rec.Key).ReadAllText();
await FileA.Get(rec.Key).CopyTo<FileB>();
await FileA.Get(rec.Key).MoveTo<FileB>();

// Other instance ops
var bytes = await FileA.Get(rec.Key).ReadAllBytes();
var head  = await FileA.Get(rec.Key).Head(); // ObjectStat

Contract

  • Inputs: key, optional name, content (string / byte[] / Stream / object for JSON), optional contentType.
  • Outputs: IStorageObject with metadata (Id, Key, Name, ContentType, Size, ContentHash, CreatedAt, UpdatedAt, Provider, Container, Tags).
  • Errors: Unknown profile/container → throws; missing key → null for Head, false for Delete; invalid range → throws. Hash computed only on seekable streams.

Service helpers (alternative)

The same primitives are available directly on IStorageService.

await storage.CreateTextFile("doc.txt", "hello", profile: "main");
var text = await storage.ReadAllText("main", "", "doc.txt");
var stat = await storage.HeadAsync("main", "", "doc.txt");
await storage.CopyTo("hot", "", "doc.txt", "cold");

Behavioral notes and edge cases

  • Defaults and fallbacks: If profile is omitted, DefaultProfile is used when set; with exactly one profile, SingleProfileOnly fallback applies.
  • Validation: With ValidateOnStart=true, misconfigurations fail fast during app start.
  • Large payloads: Use ReadRangeAsString / ReadRangeAsync to avoid loading entire content.
  • Capabilities: Local provider supports lightweight stat and server-side copy; presign is unsupported.

References

  • Reference: docs/reference/storage.md
  • Decisions: STOR-0001, STOR-0006, STOR-0007, DATA-0061, ARCH-0040

Changes from Previous Version

No structural changes between v0.8.0 and v0.17.0.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 1 target framework; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.