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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Decode.Storage.Abstractions" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Decode.Storage.Abstractions" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Decode.Storage.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Decode.Storage.Abstractions --version 3.0.0
                    
#r "nuget: Decode.Storage.Abstractions, 3.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Decode.Storage.Abstractions@3.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Decode.Storage.Abstractions&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Decode.Storage.Abstractions&version=3.0.0
                    
Install as a Cake Tool

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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.

Version Downloads Last Updated
3.0.0 130 9/14/2026
2.1.0 151 9/13/2026
2.0.2 149 9/13/2026
2.0.1 151 9/13/2026
2.0.0 198 7/28/2026
1.0.3 199 6/22/2026