Katalyst.Library.FileStorage
1.0.0
dotnet add package Katalyst.Library.FileStorage --version 1.0.0
NuGet\Install-Package Katalyst.Library.FileStorage -Version 1.0.0
<PackageReference Include="Katalyst.Library.FileStorage" Version="1.0.0" />
<PackageVersion Include="Katalyst.Library.FileStorage" Version="1.0.0" />
<PackageReference Include="Katalyst.Library.FileStorage" />
paket add Katalyst.Library.FileStorage --version 1.0.0
#r "nuget: Katalyst.Library.FileStorage, 1.0.0"
#:package Katalyst.Library.FileStorage@1.0.0
#addin nuget:?package=Katalyst.Library.FileStorage&version=1.0.0
#tool nuget:?package=Katalyst.Library.FileStorage&version=1.0.0
Katalyst.Library.FileStorage
Overview
Library.FileStorage is a small abstraction over blob/object storage that lets you switch between a local filesystem, Amazon S3, or Azure Blob Storage using configuration only.
Capabilities
- Unified API — Work against
IFileStorageinstead of wiring S3, Azure, or disk paths directly. - Configuration-driven provider — Choose
Local,S3, orAzureviaStorage:Provider(comparison is case-insensitive). - Optional key prefix — Each provider supports a
Prefixso logical keys share a virtual folder under the root, bucket, or container. - Stream-based I/O — Upload and download use
Stream; callers dispose streams returned fromOpenReadAsync.
Configuration shape
{
"Storage": {
"Provider": "Local",
"Local": {
"RootPath": "C:\\app-data\\blobs",
"Prefix": ""
},
"AmazonS3": {
"BucketName": "my-app-bucket",
"Region": "us-east-1",
"Prefix": "uploads",
"Credentials": {
"Enabled": false,
"AccessKeyId": "",
"SecretAccessKey": "",
"CredentialsEncrypted": false
}
},
"AzureBlob": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net",
"ContainerName": "my-container",
"Prefix": "uploads"
}
}
}
Everything sits under the Storage section (see StorageSettings). Provider selects the implementation: Local, S3, or Azure. The value must be set; if it is missing or empty, registration throws InvalidOperationException. Only the subsection for the active provider must be valid—you can keep all three subsections in one file and switch Provider between environments; unused subsections are not read at runtime.
Local— UsesStorage:Local(RootPath, optionalPrefix). Resolves relativeRootPathunder the consuming app’s project directory when an SDK project file can be found by walking up fromAppContext.BaseDirectory; otherwise underAppContext.BaseDirectory(typical for published apps).S3— UsesStorage:AmazonS3(BucketName, optionalRegion,Prefix, and optionalCredentials). WhenCredentials:Enabledis false (default),IAmazonS3is created with the AWS SDK default credential chain. WhenCredentials:Enabledis true, the client usesAccessKeyIdandSecretAccessKeyafter optional decryption (see Amazon S3 provider section).AddAppFileStorageregistersIStorageSecretResolver(defaultStorageSecretResolver) unless the host already registered one.Azure— UsesStorage:AzureBlob(ConnectionString,ContainerName, optionalPrefix).
Calling AddAppFileStorage registers IFileStorage as a singleton for the selected provider and binds that provider’s options with services.Configure<TOptions>(configuration.GetSection(...)). It also registers IStorageSecretResolver once (see the S3 section) so encrypted configuration values can be resolved when needed.
IFileStorage methods
| Method | Description |
|---|---|
UploadAsync |
Writes or overwrites the object at key from content. Optional contentType is passed through when the provider supports it (S3, Azure). |
OpenReadAsync |
Returns a readable stream; the caller must dispose it. Local throws FileNotFoundException if the key is missing; cloud providers surface their client errors similarly. |
DeleteAsync |
Deletes the object if it exists; no error when the key is already absent. |
ExistsAsync |
Returns whether an object exists at key. |
Logical keys use / as a path separator where relevant; the local provider normalizes to the platform directory separator and rejects . / .. segments and paths that escape the configured root.
Local provider
When it runs
Selected when Storage:Provider is Local. Registers LocalFileStorage as IFileStorage.
How it works
- Objects are files under
RootPath, with optionalPrefixapplied to every key (seePrefixedObjectKey). RootPath— If absolute, it is normalized and used as the root. If relative, it is combined with the resolved anchor directory (project folder containing*.csproj/*.vbproj/*.fsprojwhen found, elseAppContext.BaseDirectory), so a value like"storage"often lands next to your project duringdotnet run.Prefix— Optional subdirectory prefix for all keys (like a folder).- Uploads create parent directories as needed. Keys that would resolve outside the root throw
ArgumentException.
Configuration example
{
"Storage": {
"Provider": "Local",
"Local": {
"RootPath": "C:\\app-data\\blobs",
"Prefix": ""
}
}
}
Paths that must not use the project-directory heuristic
For anchors such as ASP.NET content root instead of the project folder, set RootPath to an absolute path you compute at startup (for example Path.Combine(builder.Environment.ContentRootPath, "App_Data", "files")).
Amazon S3 provider
When it runs
Selected when Storage:Provider is S3. Registers IAmazonS3 (singleton client) and AmazonS3FileStorage as IFileStorage.
How it works
- Uses
PutObject,GetObject,DeleteObject, and existence checks against the configured bucket. Region— When omitted or empty, the client defaults tous-east-1(RegionEndpoint.USEast1).Prefix— Optional object key prefix applied to every logical key.Credentials— Optional explicit IAM user keys:Enabled—false: use the SDK default credential chain (environment variables, shared credentials file, IAM roles on AWS, and so on).true: useAccessKeyIdandSecretAccessKey(both required).CredentialsEncrypted—false: keys are plain text in configuration.true: values are ciphertext produced byStorageSecretCryptography.Encrypt; they are decrypted throughIStorageSecretResolverwhen theIAmazonS3singleton is created.
Configuration example
{
"Storage": {
"Provider": "S3",
"AmazonS3": {
"BucketName": "my-app-bucket",
"Region": "us-east-1",
"Prefix": "uploads",
"Credentials": {
"Enabled": false,
"AccessKeyId": "",
"SecretAccessKey": "",
"CredentialsEncrypted": false
}
}
}
}
Configuration example (explicit keys, plain text)
{
"Storage": {
"Provider": "S3",
"AmazonS3": {
"BucketName": "my-app-bucket",
"Region": "us-east-1",
"Credentials": {
"Enabled": true,
"AccessKeyId": "AKIA...",
"SecretAccessKey": "...",
"CredentialsEncrypted": false
}
}
}
}
Requirements
- A reachable bucket matching
BucketName. - Either
Credentials:Enabledisfalseand credentials are available to the default credential chain, orEnabledistruewith non-emptyAccessKeyIdandSecretAccessKey(decrypted automatically whenCredentialsEncryptedistrue).
Azure Blob Storage provider
When it runs
Selected when Storage:Provider is Azure. Registers AzureBlobFileStorage as IFileStorage.
How it works
- Uses
Azure.Storage.BlobswithConnectionStringandContainerName. Prefix— Optional blob name prefix (virtual folder) applied to every logical key.
Configuration example
{
"Storage": {
"Provider": "Azure",
"AzureBlob": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net",
"ContainerName": "my-container",
"Prefix": "uploads"
}
}
}
Requirements
- A valid storage account connection string and an existing or creatable container name, as enforced by the Azure client at runtime.
Examples
ASP.NET Core (minimal hosting)
using Library.FileStorage.Contracts;
using Library.FileStorage.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAppFileStorage(builder.Configuration);
var app = builder.Build();
app.MapGet("/exists/{**key}", async (IFileStorage storage, string key, CancellationToken ct) =>
{
var exists = await storage.ExistsAsync(key, ct);
return Results.Ok(new { key, exists });
});
app.Run();
appsettings.json
{
"Storage": {
"Provider": "Local",
"Local": {
"RootPath": "storage",
"Prefix": "app"
}
}
}
Switch to S3 or Azure by setting "Provider" to "S3" or "Azure" and filling in Storage:AmazonS3 or Storage:AzureBlob as in the provider sections above.
Class library or tests (manual Configuration + ServiceCollection)
Use this when you do not have WebApplicationBuilder but still want the same registration:
using Library.FileStorage.Contracts;
using Library.FileStorage.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false)
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Storage:Provider"] = "Local",
["Storage:Local:RootPath"] = Path.Combine(Path.GetTempPath(), "file-storage-tests")
})
.Build();
var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);
services.AddLogging();
services.AddAppFileStorage(configuration);
await using var provider = services.BuildServiceProvider();
var storage = provider.GetRequiredService<IFileStorage>();
await using var upload = new MemoryStream("Hello"u8.ToArray());
await storage.UploadAsync("documents/hello.txt", upload, contentType: "text/plain");
var exists = await storage.ExistsAsync("documents/hello.txt");
await using var readStream = await storage.OpenReadAsync("documents/hello.txt");
await storage.DeleteAsync("documents/hello.txt");
For S3 or Azure in tests, set the corresponding subsection and ensure credentials or emulators (for example Azurite, LocalStack) are reachable before calling AddAppFileStorage.
Custom implementation
Register your own type instead of calling AddAppFileStorage:
services.AddSingleton<IFileStorage, MyCustomFileStorage>();
Referenced packages
The project references AWSSDK.S3, Azure.Storage.Blobs, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.Logging.Abstractions, and Microsoft.Extensions.Options.ConfigurationExtensions. Hosting apps typically already reference Microsoft.Extensions.Hosting / Microsoft.AspNetCore.App, which supply IServiceCollection extensions and IConfiguration. Unused providers still pull their cloud SDK dependencies transitively when you reference this library.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- AWSSDK.S3 (>= 4.0.23)
- Azure.Storage.Blobs (>= 12.27.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.7)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.7)
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.0 | 154 | 5/11/2026 |