File storage is the textbook abstraction-layer case in .NET. Register once with a backend — FileSystem, Azure Blob, SSH/SFTP, zip archives or GitHub — and the rest of your code keeps calling the same interface. Swap implementations without touching a single caller. The Office modules exchange files through the same Regira.IO abstractions, and Entities attachments use it as their file store.
Each backend implements IFileService. Pick the one that fits your infrastructure at registration time — the calling code never needs to change.
Local disk storage. Zero config, perfect for development and single-server deployments.
Azure Blob Storage. AzureCommunicator handles connection string and container setup.
Remote filesystems over SSH. Drop-in replacement for any SFTP-accessible storage.
Reads and writes files inside a zip archive. Useful for bundled assets or portable exports.
Uses a GitHub repository as a file store. Fetches raw file contents via the GitHub API.
Register IFileService in your DI container and point it at whichever backend fits. Production uses Azure? Development uses the filesystem? Switch by changing one line — zero caller changes.
// Register one backend. The calling code only ever sees IFileService.
// FileSystem
services.AddTransient<IFileService>(_ =>
new BinaryFileService(new BinaryFileService.FileServiceOptions {
RootFolder = ROOT_FOLDER
}));
// Azure Blob
services.AddTransient<IFileService>(_ =>
new BinaryBlobService(new AzureCommunicator(new AzureConfig {
ConnectionString = AZURE_CONNECTION_STRING,
ContainerName = BLOB_CONTAINER
})));
// SSH / SFTP
services.AddTransient<IFileService>(_ => new SftpService(/* … */));
// Zip archive
services.AddTransient<IFileService>(_ => new ZipFileService(/* … */));
// GitHub
services.AddTransient<IFileService>(p =>
new GitHubService(new GitHubOptions {
Uri = GITHUB_URI,
// Key = TOKEN_IF_REQUIRED
// RootFolder is derived from Uri (+ "/contents/")
}, p.GetRequiredService<ISerializer>()));
// Same calls, whichever backend is registered
IFileService fileService = sp.GetRequiredService<IFileService>();
IEnumerable<string> fileIdentifiers = await fileService.List();
byte[]? bytes = await fileService.GetBytes(identifier);
var path = await fileService.Save(identifier, bytes);Install Regira.IO.Storage from nuget.org alongside the backend package you need. Free to use — no license key required.
Queryable repositories, declarative search conditions, and EF Core integration — the repetitive 80% of every backend, done.