DKNet

DKNet.Svc.BlobStorage.Abstractions

Provider-agnostic blob storage contract for .NET developers — application code depends on IBlobService and the shared models, and a provider package (AWS S3, Azure Storage, or the local filesystem) supplies the implementation.

✨ Why use it?

🚀 Quick Start

Use a .NET 10 console project. This package has no IBlobService implementation of its own, so install it together with the Local provider to run the example.

dotnet new console -f net10.0 -n BlobDemo
cd BlobDemo
dotnet add package DKNet.Svc.BlobStorage.Abstractions
dotnet add package DKNet.Svc.BlobStorage.Local
dotnet add package Microsoft.Extensions.Logging
using DKNet.Svc.BlobStorage.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

var config = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["BlobStorage:LocalFolder:RootFolder"] = Path.Combine(Path.GetTempPath(), "blob-demo")
    })
    .Build();

var services = new ServiceCollection().AddLogging().AddLocalDirectoryBlobService(config);
using var provider = services.BuildServiceProvider();
var blobService = provider.GetRequiredService<IBlobService>();

var blob = new BlobDetails.BlobData("reports/hello.txt", BinaryData.FromString("Hello blob storage")) { Overwrite = true };
var location = await blobService.SaveAsync(blob);
Console.WriteLine(location); // reports/hello.txt

Run with dotnet run.

🏗️ Architecture

Application code calls IBlobService, implemented by the BlobService abstract base class, which reads BlobServiceOptions and accepts or returns BlobRequest and BlobDetails models; a provider package (S3, Azure, or Local) derives from BlobService to supply the actual backend.

This package ships no IBlobService implementation — only the contract, the shared BlobService base class, the request/result models, and BlobServiceOptions. The diagram cannot show that BlobService.ValidateFile and GetBlobLocation are protected virtual: a provider can call them as-is or override them to change the rules.

🔄 How it works

SaveAsync runs ValidateFile and GetBlobLocation in the shared BlobService base class, throws FileLoadException when a BlobServiceOptions rule is violated, and otherwise hands the normalized name to the provider override, which writes to its backing store and returns the location.

Every SaveAsync call runs the same two shared steps before a provider ever touches its backing store, and only the last step differs per backend. The diagram does not show the streaming path: SaveAsync(BlobData) is the abstract member each provider implements, and the default SaveAsync(BlobStreamData) buffers the stream into BinaryData and delegates to it, so the same validation and location logic applies to both.

🧩 Features