Storage.Vector 1.0.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package Storage.Vector --version 1.0.3
                    
NuGet\Install-Package Storage.Vector -Version 1.0.3
                    
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="Storage.Vector" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Storage.Vector" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Storage.Vector" />
                    
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 Storage.Vector --version 1.0.3
                    
#r "nuget: Storage.Vector, 1.0.3"
                    
#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 Storage.Vector@1.0.3
                    
#: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=Storage.Vector&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Storage.Vector&version=1.0.3
                    
Install as a Cake Tool

Storage.Vector

A portable .NET 8 storage provider abstraction and implementations for Azure Blob Storage (including local Azurite emulation) and Local Filesystem (supporting local directories, NAS, and SMB/NFS mounts). Supports secondary/backup storage mirroring, presigned download URLs, path traversal protection, and validation.

CI NuGet License: PolyForm Noncommercial


Features

  • 📁 Unified interface — swap between local directories, NAS, and cloud providers purely via configuration
  • ☁️ Azurite & Azure support — fully compatible with local Azurite emulator for dev/testing and cloud Azure Blob Storage
  • 🔒 Path traversal protection — local provider containment checks prevent directory breakout attacks
  • 👯 Keyed secondary mirroring — configure and inject independent backup/sync storage targets via keyed DI
  • 🔑 Presigned URLs — generate signed download URLs (HMAC-SHA256 signatures for LocalFile, SAS tokens for Azure)
  • ⚙️ Startup validation — throws clear errors on application boot if options or paths are missing
  • 📦 NuGet-ready — structured for dotnet pack with symbols (.snupkg)
  • 💉 DI-friendly — integrates with Microsoft.Extensions.DependencyInjection via AddStorageProvider()
  • 🛡️ Unified error handling — catches and translates underlying API exceptions into a structured StorageException

Quick Start

Install

dotnet add package Storage.Vector

Register with Dependency Injection

To register the primary storage provider:

// Program.cs / Startup.cs
builder.Services.AddStorageProvider(builder.Configuration);

Configure the provider options in your settings:

// appsettings.json
{
  "Storage": {
    "Provider": "LocalFile", // "LocalFile" or "AzureBlob"
    "Container": "uploads",
    "Local": {
      "RootPath": "C:\\ProgramData\\MyApp\\Storage",
      "PublicBaseUrl": "https://localhost:5001/api/v1/storage",
      "SigningKey": "your-hmac-sha256-signing-key-minimum-32-chars-long"
    }
  }
}

Upload and Download Files

Inject IStorageProvider into your services:

public class DocumentService(IStorageProvider storage)
{
    public async Task SaveFileAsync(string key, Stream data, CancellationToken ct)
    {
        await storage.PutObjectAsync("documents", key, data, "application/pdf", ct);
    }

    public async Task<Stream> ReadFileAsync(string key, CancellationToken ct)
    {
        return await storage.GetObjectAsync("documents", key, ct);
    }
}

Register a Keyed Secondary Provider (Backup Sync)

// Register Primary IStorageProvider
builder.Services.AddStorageProvider(builder.Configuration);

// Register Secondary Keyed IStorageProvider ("secondary")
builder.Services.AddSecondaryStorageProvider(builder.Configuration);

Configure both in settings:

{
  "Storage": {
    "Provider": "LocalFile",
    "Container": "uploads",
    "Local": {
      "RootPath": "C:\\Storage\\Primary",
      "PublicBaseUrl": "https://localhost:5001/storage",
      "SigningKey": "primary-key"
    },
    "Secondary": {
      "Provider": "AzureBlob",
      "Container": "backups",
      "Azure": {
        "ConnectionString": "UseDevelopmentStorage=true"
      }
    }
  }
}

Resolve the secondary provider using the SecondaryProviderKey constant:

public class SyncService(
    IStorageProvider primary,
    [FromKeyedServices(StorageServiceCollectionExtensions.SecondaryProviderKey)] IStorageProvider secondary)
{
    public async Task MirrorAsync(string key, CancellationToken ct)
    {
        using var data = await primary.GetObjectAsync("documents", key, ct);
        await secondary.PutObjectAsync("documents", key, data, "application/octet-stream", ct);
    }
}

Without DI (direct use)

// LocalFile
var localOptions = Options.Create(new StorageOptions
{
    Provider = "LocalFile",
    RootPath = "C:\\Storage",
    PublicBaseUrl = "https://localhost:5001/storage",
    SigningKey = "secret-signing-key"
});
IStorageProvider localProvider = new LocalFileStorageProvider(localOptions);

// AzureBlob
var azureOptions = Options.Create(new StorageOptions
{
    Provider = "AzureBlob",
    Container = "media",
    ConnectionString = "UseDevelopmentStorage=true"
});
var client = new BlobServiceClient(azureOptions.Value.ConnectionString);
IStorageProvider azureProvider = new AzureBlobStorageProvider(client, azureOptions);

Detailed API & Options Reference

Generating and Validating Presigned URLs

Generate a URL that routes download requests through your local endpoint and validates them with a signature:

// Generate
var url = await storage.GetPresignedUrlAsync("documents", "invoice.pdf", TimeSpan.FromMinutes(15), ct);

// Validate (in your Controller/Endpoint)
var signer = new LocalFileUrlSigner(options.Value.SigningKey);
var requestUrl = $"{Request.Path}{Request.QueryString}";

if (!signer.VerifyUrl(requestUrl))
{
    return Forbid("Presigned URL is expired or has an invalid signature.");
}

Unified Exception Handling

All underlying filesystem or Azure SDK network/authorization errors are mapped into a StorageException containing a StorageErrorKind enum:

try
{
    await storage.GetObjectAsync("documents", "missing.pdf", ct);
}
catch (StorageException ex)
{
    switch (ex.ErrorKind)
    {
        case StorageErrorKind.NotFound:
            Console.WriteLine("File or container not found.");
            break;
        case StorageErrorKind.AccessDenied:
            Console.WriteLine("Unauthorized access to storage path.");
            break;
        case StorageErrorKind.Transient:
            Console.WriteLine("Transient network issue. Retry later.");
            break;
        default:
            Console.WriteLine($"Storage operation failed: {ex.Message}");
            break;
    }
}

Configuration

Option Type Default Description
Storage:Provider string (None) Storage engine selection: "LocalFile" or "AzureBlob"
Storage:Container string (None) Default container/folder name to build roots in
Storage:Local:RootPath string (None) Directory containing storage containers (LocalFile only)
Storage:Local:PublicBaseUrl string (None) Base URL to route signed requests (LocalFile only)
Storage:Local:SigningKey string (None) Secret key used to sign URLs (LocalFile only)
Storage:Azure:ConnectionString string (None) Storage Account Connection String (AzureBlob only)
Storage:Azure:PublicBlobEndpoint string (None) Optional CDN public blob endpoint overlay (AzureBlob only)

License

This project is licensed under the PolyForm Noncommercial License 1.0.0.

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 was computed.  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 was computed.  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.

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.1.0 114 8/1/2026
1.0.5 163 7/21/2026
1.0.4 109 7/21/2026
1.0.3 399 7/13/2026
1.0.2 105 7/13/2026
1.0.1 114 7/13/2026
1.0.0 122 7/13/2026