Packages Reference
Vali-Blob is distributed as a family of 12 focused NuGet packages. Install only what your project needs. All packages target net8.0 and net9.0 and are versioned together — always use the same version across all Vali-Blob packages in a project.
Summary Table
| Package | Required | Cloud Dependency | Supports Resumable | Supports Presigned URLs |
|---|---|---|---|---|
Vali-Blob.Core | Always | None | — | — |
Vali-Blob.AWS | When using S3 | AWSSDK.S3 | Yes | Yes |
Vali-Blob.Azure | When using Azure | Azure.Storage.Blobs | Yes | Yes (SAS tokens) |
Vali-Blob.GCP | When using GCP | Google.Cloud.Storage.V1 | Yes | Yes (V4 signed URLs) |
Vali-Blob.OCI | When using OCI | Oracle SDK | Yes | Yes (PARs via API) |
Vali-Blob.Supabase | When using Supabase | supabase-csharp | No | Yes |
Vali-Blob.Local | For local/dev | None | Yes | Yes (HTTP) |
Vali-Blob.Redis | For Redis sessions | StackExchange.Redis | Session Store | — |
Vali-Blob.EFCore | For DB sessions | EF Core | Session Store | — |
Vali-Blob.Testing | In test projects | None | Yes | Yes |
Vali-Blob.HealthChecks | For health endpoints | ASP.NET Core | — | — |
Vali-Blob.ImageSharp | For image processing | SixLabors.ImageSharp | — | — |
Vali-Blob.Core
The foundation package. Every Vali-Blob project requires this package.
dotnet add package Vali-Blob.Core
What it provides:
IStorageProvider— the core storage interface with 11 operationsIStorageFactory— resolves named providers by keyBaseStorageProvider— base class with pipeline execution, resilience hooks, and telemetryStorageResult<T>/StorageResult— explicit result/error pattern, no exceptions for expected failuresStoragePath— safe path building with date/hash/random suffixes and sanitizationStorageErrorCode— enum of all well-known error conditionsStoragePipelineBuilder— fluent middleware registration- DI extension methods:
AddVali-Blob(),AddProvider<T>(),WithPipeline() IResumableUploadProvider— optional interface for resumable upload supportIPresignedUrlProvider— optional interface for presigned URL generation- All request/response types:
UploadRequest,DownloadRequest,FileMetadata,FileEntry,UploadResult - Event system:
IStorageEventHandler<T>,StorageEventContext
Key dependencies:
| Dependency | Purpose |
|---|---|
Microsoft.Extensions.DependencyInjection.Abstractions | DI integration |
Microsoft.Extensions.Options | Options pattern |
Microsoft.Extensions.Logging.Abstractions | Structured logging |
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Required | Yes — always install this |
| External cloud dependency | None |
Vali-Blob.AWS
Amazon S3 provider implementation.
dotnet add package Vali-Blob.Core
dotnet add package Vali-Blob.AWS
What it provides:
AWSS3Provider— fullIStorageProvider+IResumableUploadProvider+IPresignedUrlProviderimplementationAWSS3Options— provider configuration:
builder.Services
.AddVali-Blob(o => o.DefaultProvider = "aws")
.AddProvider<AWSS3Provider>("aws", opts =>
{
opts.BucketName = "my-bucket";
opts.Region = "us-east-1";
opts.AccessKey = config["AWS:AccessKey"]!;
opts.SecretKey = config["AWS:SecretKey"]!;
opts.ServiceUrl = null; // set to "http://localhost:4566" for LocalStack
});
AWSS3Options fields:
| Field | Type | Description |
|---|---|---|
BucketName | string | S3 bucket name |
Region | string | AWS region code (e.g., us-east-1) |
AccessKey | string? | AWS access key (leave null to use IAM role) |
SecretKey | string? | AWS secret key (leave null to use IAM role) |
ServiceUrl | string? | Override endpoint URL (for LocalStack, MinIO, etc.) |
ForcePathStyle | bool | Use path-style URLs instead of virtual-hosted; required for LocalStack |
Key dependency: AWSSDK.S3
In production on AWS (EC2, ECS, Lambda), do not set AccessKey and SecretKey. Leave them null and grant the instance/task IAM role the necessary S3 permissions. This is more secure and eliminates credential rotation.
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supports resumable uploads | Yes (S3 multipart upload) |
| Supports presigned URLs | Yes |
Vali-Blob.Azure
Azure Blob Storage provider implementation.
dotnet add package Vali-Blob.Core
dotnet add package Vali-Blob.Azure
What it provides:
AzureBlobProvider— fullIStorageProvider+IResumableUploadProvider+IPresignedUrlProviderAzureBlobOptions:
.AddProvider<AzureBlobProvider>("azure", opts =>
{
opts.ConnectionString = config["Azure:ConnectionString"]!;
opts.ContainerName = "my-container";
})
AzureBlobOptions fields:
| Field | Type | Description |
|---|---|---|
ConnectionString | string | Azure Storage connection string |
ContainerName | string | Blob container name |
CreateContainerIfNotExists | bool | Auto-create the container on startup (default: false) |
Key dependency: Azure.Storage.Blobs
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supports resumable uploads | Yes (block blob uncommitted blocks) |
| Supports presigned URLs | Yes (SAS tokens) |
Vali-Blob.GCP
Google Cloud Storage provider implementation.
dotnet add package Vali-Blob.Core
dotnet add package Vali-Blob.GCP
What it provides:
GCPStorageProvider— fullIStorageProvider+IResumableUploadProvider+IPresignedUrlProviderGCPStorageOptions:
.AddProvider<GCPStorageProvider>("gcp", opts =>
{
opts.ProjectId = config["GCP:ProjectId"]!;
opts.BucketName = config["GCP:BucketName"]!;
opts.JsonCredentials = File.ReadAllText("/secrets/gcp-sa.json");
})
GCPStorageOptions fields:
| Field | Type | Description |
|---|---|---|
ProjectId | string | Google Cloud project ID |
BucketName | string | GCS bucket name |
JsonCredentials | string? | Service account JSON (leave null to use Application Default Credentials) |
Key dependency: Google.Cloud.Storage.V1
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supports resumable uploads | Yes (GCS resumable upload sessions) |
| Supports presigned URLs | Yes (V4 signed URLs) |
Vali-Blob.OCI
Oracle Cloud Infrastructure Object Storage provider.
dotnet add package Vali-Blob.Core
dotnet add package Vali-Blob.OCI
What it provides:
OCIStorageProvider—IStorageProvider+IResumableUploadProviderOCIStorageOptions— OCI tenancy OCID, region, bucket, and API key configuration
OCIStorageOptions fields:
| Field | Type | Description |
|---|---|---|
TenancyId | string | OCI tenancy OCID |
UserId | string | OCI user OCID |
Fingerprint | string | API key fingerprint |
PrivateKey | string | PEM-encoded private key content |
Region | string | OCI region identifier (e.g., us-ashburn-1) |
BucketName | string | Object Storage bucket name |
Namespace | string | Object Storage namespace |
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supports resumable uploads | Yes (OCI multipart uploads) |
| Supports presigned URLs | Yes — via OCI Pre-Authenticated Requests (PARs). Unlike AWS/GCP, each URL requires an API call to OCI (no local signing). |
Vali-Blob.Supabase
Supabase Storage provider implementation.
dotnet add package Vali-Blob.Core
dotnet add package Vali-Blob.Supabase
What it provides:
SupabaseStorageProvider—IStorageProvider+IPresignedUrlProviderSupabaseStorageOptions:
.AddProvider<SupabaseStorageProvider>("supabase", opts =>
{
opts.Url = config["Supabase:Url"]!; // https://xyz.supabase.co
opts.ServiceKey = config["Supabase:ServiceKey"]!; // service_role key
opts.BucketName = "user-uploads";
})
Key dependency: supabase-csharp
SupabaseStorageProvider does not implement IResumableUploadProvider natively. For resumable uploads with Supabase, use Vali-Blob's own chunking layer by storing session state in Redis or EF Core and pointing the resumable upload endpoint at the Supabase provider.
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supports resumable uploads | No (use Vali-Blob chunking layer) |
| Supports presigned URLs | Yes (signed URLs) |
Vali-Blob.Local
Local filesystem storage provider for development and on-premise deployments.
dotnet add package Vali-Blob.Core
dotnet add package Vali-Blob.Local
What it provides:
LocalStorageProvider—IStorageProvider+IResumableUploadProvider+IPresignedUrlProviderLocalStorageOptions:
.AddProvider<LocalStorageProvider>("local", opts =>
{
opts.BasePath = Path.Combine(builder.Environment.ContentRootPath, "storage");
opts.CreateIfNotExists = true;
opts.PublicBaseUrl = "https://localhost:5001/storage";
})
- Metadata stored as
.meta.jsonsidecar files alongside each stored object - Resumable uploads via chunk staging directories under
BasePath/.chunks/ - Presigned URLs are signed HTTP URLs pointing to a local static files endpoint
LocalStorageOptions fields:
| Field | Type | Default | Description |
|---|---|---|---|
BasePath | string | Required | Root directory for all stored files |
CreateIfNotExists | bool | false | Create BasePath if it does not exist |
PublicBaseUrl | string? | null | Base URL for generating public file URLs |
Key dependency: None (pure .NET, no external SDK)
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supports resumable uploads | Yes |
| Supports presigned URLs | Yes (local HTTP signed URLs) |
| External cloud dependency | None |
Vali-Blob.Redis
Redis-backed resumable upload session store.
dotnet add package Vali-Blob.Redis
What it provides:
RedisResumableSessionStore— implementsIResumableSessionStoreRedisSessionStoreOptions— connection string, key prefix, and TTLAddRedisSessionStore()DI extension
builder.Services
.AddVali-Blob(...)
.AddRedisSessionStore(opts =>
{
opts.ConnectionString = config["Redis:ConnectionString"]!;
opts.KeyPrefix = "valiblob:sessions:";
opts.Ttl = TimeSpan.FromHours(24);
});
When to use: Horizontally scaled applications (multiple instances) where resumable upload sessions must survive load balancer routing to different instances. Redis provides fast, shared session state with automatic expiry.
Key dependency: StackExchange.Redis
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Minimum Redis version | 6.0 |
| Session expiry | Configurable TTL (default: 24 hours) |
Vali-Blob.EFCore
Entity Framework Core resumable upload session store.
dotnet add package Vali-Blob.EFCore
What it provides:
EfCoreResumableSessionStore— implementsIResumableSessionStoreResumableSessionDbContext— EF CoreDbContextwithResumableSessionstableAddEfCoreSessionStore<TContext>()DI extension- EF Core migration support
// Register with your existing DbContext
builder.Services
.AddVali-Blob(...)
.AddEfCoreSessionStore<AppDbContext>();
// Or with the built-in standalone context
builder.Services
.AddDbContext<ResumableSessionDbContext>(o =>
o.UseNpgsql(config.GetConnectionString("Default")))
.AddEfCoreSessionStore<ResumableSessionDbContext>();
Apply the migration to create the sessions table:
dotnet ef migrations add AddResumableSessions
dotnet ef database update
When to use: Applications that already use EF Core and want sessions persisted to their existing relational database, with no need for a Redis cluster.
Key dependency: Microsoft.EntityFrameworkCore
Supported databases: PostgreSQL, MySQL, SQL Server, SQLite, and any EF Core provider.
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Requires migration | Yes |
| Supported databases | Any EF Core provider |
Vali-Blob.Testing
In-memory storage provider for unit and integration tests.
dotnet add package Vali-Blob.Testing
What it provides:
InMemoryStorageProvider— in-process, dictionary-backed implementation ofIStorageProviderandIResumableUploadProvider- Pre-seeding helpers for test setup:
var provider = new InMemoryStorageProvider();
// Seed a file with content
provider.Seed("uploads/avatar.jpg", Encoding.UTF8.GetBytes("fake-image-bytes"));
// Seed metadata
provider.SeedMetadata("uploads/avatar.jpg", new FileMetadata
{
SizeBytes = 1024,
ContentType = "image/jpeg"
});
- Inspection helpers for assertions:
// Assert file was uploaded
Assert.True(provider.Contains("uploads/avatar.jpg"));
// Assert file content
var bytes = provider.GetBytes("uploads/avatar.jpg");
Assert.Equal(expectedBytes, bytes);
// Get all stored paths
var allPaths = provider.GetAll().Select(e => e.Path);
When to use: Every test project. The in-memory provider is deterministic, instantaneous, and requires no infrastructure. Inject it via DI using AddVali-Blob().AddProvider<InMemoryStorageProvider>("test").
Create a new InMemoryStorageProvider instance per test (or test class) to prevent state leakage between tests.
Key dependency: None (Vali-Blob.Core only)
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Thread-safe | Yes |
| For production use | No — test projects only |
Vali-Blob.HealthChecks
ASP.NET Core health check integration for storage providers.
dotnet add package Vali-Blob.HealthChecks
What it provides:
ValiBloBHealthCheck— implementsIHealthCheck, probes a provider by callingExistsAsyncon a canary pathAddVali-Blob()extension onIHealthChecksBuilder
builder.Services
.AddHealthChecks()
.AddVali-Blob("aws-storage",
provider: serviceProvider => serviceProvider
.GetRequiredService<IStorageFactory>().Create("aws"),
failureStatus: HealthStatus.Unhealthy,
tags: ["storage", "aws"]);
app.MapHealthChecks("/health");
When to use: Any production ASP.NET Core application. Expose storage provider health via /health for Kubernetes liveness/readiness probes, uptime monitors, or operations dashboards.
Key dependency: Microsoft.Extensions.Diagnostics.HealthChecks
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| ASP.NET Core version | 8.0+ |
Vali-Blob.ImageSharp
Image processing pipeline middleware using SixLabors.ImageSharp.
dotnet add package Vali-Blob.ImageSharp
What it provides:
ImageProcessingMiddleware— upload-time image resize, format conversion, and thumbnail generationImageProcessingOptions— processing configurationUseImageProcessing()pipeline extension method
.WithPipeline(p => p
.UseValidation(v => v.AllowedExtensions = [".jpg", ".png", ".webp"])
.UseImageProcessing(img =>
{
img.ResizeWidth = 1280;
img.ResizeHeight = 720;
img.OutputFormat = ImageFormat.WebP;
img.Quality = 85;
img.GenerateThumbnail = true;
img.ThumbnailWidth = 200;
img.ThumbnailHeight = 200;
})
.UseConflictResolution(ConflictResolution.ReplaceExisting)
)
ImageProcessingOptions fields:
| Field | Type | Default | Description |
|---|---|---|---|
ResizeWidth | int? | null | Target width in pixels (null = no resize) |
ResizeHeight | int? | null | Target height in pixels (null = no resize) |
OutputFormat | ImageFormat? | null | Convert to this format (null = keep original) |
Quality | int | 85 | JPEG/WebP quality (1–100) |
GenerateThumbnail | bool | false | Also store a thumbnail |
ThumbnailWidth | int | 200 | Thumbnail width in pixels |
ThumbnailHeight | int | 200 | Thumbnail height in pixels |
| Property | Value |
|---|---|
| Target frameworks | net8.0; net9.0 |
| Supported input formats | JPEG, PNG, GIF, BMP, TIFF, WebP |
| Supported output formats | JPEG, PNG, WebP, AVIF |
| Key dependency | SixLabors.ImageSharp |