Decode.Storage.Abstractions
3.0.0
dotnet add package Decode.Storage.Abstractions --version 3.0.0
NuGet\Install-Package Decode.Storage.Abstractions -Version 3.0.0
<PackageReference Include="Decode.Storage.Abstractions" Version="3.0.0" />
<PackageVersion Include="Decode.Storage.Abstractions" Version="3.0.0" />
<PackageReference Include="Decode.Storage.Abstractions" />
paket add Decode.Storage.Abstractions --version 3.0.0
#r "nuget: Decode.Storage.Abstractions, 3.0.0"
#:package Decode.Storage.Abstractions@3.0.0
#addin nuget:?package=Decode.Storage.Abstractions&version=3.0.0
#tool nuget:?package=Decode.Storage.Abstractions&version=3.0.0
Decode.Storage.Abstractions
Core abstractions and interfaces for the Decode.Storage ecosystem, providing contracts for file management in .NET.
📦 Installation
dotnet add package Decode.Storage.Abstractions
🛠️ Components
IStorageService
Defines the contract for storing, retrieving, checking, and deleting files agnostic to the underlying storage provider (Local FileSystem, Azure Blob Storage, AWS S3, etc.).
public interface IStorageService
{
Task<string> UploadAsync(string path, Stream content, string? contentType = null, CancellationToken cancellationToken = default);
Task<StorageFile?> DownloadAsync(string path, CancellationToken cancellationToken = default);
Task<bool> ExistsAsync(string path, CancellationToken cancellationToken = default);
Task<bool> DeleteAsync(string path, CancellationToken cancellationToken = default);
Task<string> GetUrlAsync(string path, DateTimeOffset? expiration = null, CancellationToken cancellationToken = default);
}
StorageFile
A lightweight record wrapping the file stream and basic metadata. It implements IDisposable and IAsyncDisposable to ensure the file stream is properly disposed of after consumption.
public record StorageFile(Stream Content, string ContentType, string FileName, long Length) : IDisposable, IAsyncDisposable;
IFileValidator & FileSignatureValidator
Provides secure, low-overhead file type validation by inspecting file magic numbers (signatures) instead of relying solely on the file extension or the client-supplied content type. It incorporates a blocklist of dangerous executable headers (such as Windows PE/MZ, Linux ELF, Java Bytecode, and shell shebangs) to prevent MIME-spoofing and script execution attacks.
public interface IFileValidator
{
Task<bool> IsValidAsync(Stream stream, string fileName, IEnumerable<string> allowedExtensions, CancellationToken cancellationToken = default);
}
Example Usage
public class UploadService
{
private readonly IFileValidator _fileValidator;
private readonly IStorageService _storageService;
public UploadService(IFileValidator fileValidator, IStorageService storageService)
{
_fileValidator = fileValidator;
_storageService = storageService;
}
public async Task SaveAvatarAsync(string fileName, Stream fileStream)
{
string[] allowedExtensions = [".png", ".jpg", ".jpeg"];
// Validates signatures and ensures the file is not an executable, even if renamed to .png
if (!await _fileValidator.IsValidAsync(fileStream, fileName, allowedExtensions))
{
throw new SecurityException("Malicious or unsupported file type detected.");
}
// Proceed to upload securely
await _storageService.UploadAsync($"avatars/{fileName}", fileStream);
}
}
The stream must support seeking — IsValidAsync reads the first 16 bytes and restores the original
position so the content can still be uploaded afterwards, and throws InvalidOperationException on a
non-seekable stream rather than consuming it. IFormFile.OpenReadStream() satisfies this.
What the validation does and does not cover
Validation runs in three steps: the extension must be in allowedExtensions; the header is matched
against the executable blocklist and rejected on any hit; then, if the extension is present in the
signature database, the header must match one of its signatures.
That last condition is the limitation worth knowing: an allowed extension with no mapped signature passes on the blocklist check alone. Empty files are rejected outright.
| Mapped | .png .jpg .jpeg .gif .bmp .pdf .zip .docx .xlsx .pptx .rar .7z .mp3 .wav .xml |
|---|---|
| Not mapped | everything else — including .svg (which can carry inline script), the legacy Office formats .doc and .xls, and plain .txt or .csv |
Two consequences follow. Allowing .svg gets you the blocklist only, not a guarantee the payload is
inert — sanitize SVG separately or serve it with Content-Disposition: attachment. And the OpenXML
formats share the ZIP signature, so a .docx check cannot distinguish a real document from any other
zip archive renamed to .docx.
This is header inspection, not a sandbox or a malware scanner. Treat it as one layer: it defeats the
common case of an executable renamed to .png, and nothing more.
📖 Why Abstractions?
By depending on IStorageService, your application services and business domain remain completely decoupled from specific cloud storage SDKs or physical disk access patterns, enabling seamless switching between Local FileSystem for development/testing and Cloud Storage for production.
📄 License
MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Decode.Storage.Abstractions:
| Package | Downloads |
|---|---|
|
Decode.Storage.AzureBlob
Azure Blob Storage implementation of IStorageService for the Decode ecosystem. |
|
|
Decode.Storage.FileSystem
Local FileSystem implementation of IStorageService for the Decode ecosystem. |
GitHub repositories
This package is not used by any popular GitHub repositories.