Skip to content

Storage Providers

MediaMatic provides a Virtual File System (VFS) abstraction supporting multiple storage providers with a unified API.

Supported Providers

ProviderVfsProviderTypeConnection String Prefix
AWS S3S3s3://
Google Cloud StorageGCPgcp://
MinIOMiniominio://
Backblaze B2B2b2://
Local File SystemLocal(path)
In-MemoryMemorymemory://
SFTPSFTPsftp://
Zip FileZipFile(path to .zip)

Creating Connections

Use VfsConnection.Create() to create connections:

csharp
using MJCZone.MediaMatic;

// Create a connection
using var vfs = VfsConnection.Create(
    VfsProviderType.S3,
    "s3://keyId=...;key=...;bucket=my-bucket;region=us-east-1"
);

AWS S3

csharp
using var s3 = VfsConnection.Create(
    VfsProviderType.S3,
    "s3://keyId=AKIAIOSFODNN7EXAMPLE;key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY;bucket=my-bucket;region=us-east-1"
);

Connection String Parameters

ParameterDescriptionRequired
keyIdAWS Access Key IDYes
keyAWS Secret Access KeyYes
bucketS3 bucket nameYes
regionAWS region (e.g., us-east-1)Yes

Using IAM Roles

For EC2/ECS with IAM roles, credentials can be omitted if the environment is configured:

csharp
using var s3 = VfsConnection.Create(
    VfsProviderType.S3,
    "s3://bucket=my-bucket;region=us-east-1"
);

Google Cloud Storage

csharp
using var gcp = VfsConnection.Create(
    VfsProviderType.GCP,
    "gcp://projectId=my-project;bucket=my-bucket;jsonKeyPath=/path/to/service-account.json"
);

Connection String Parameters

ParameterDescriptionRequired
projectIdGCP project IDYes
bucketGCS bucket nameYes
jsonKeyPathPath to service account JSONYes*

Local File System

csharp
// Absolute path
using var local = VfsConnection.Create(
    VfsProviderType.Local,
    "/var/media"
);

// Relative path
using var local = VfsConnection.Create(
    VfsProviderType.Local,
    "./uploads"
);

WARNING

Ensure the application has read/write permissions to the directory.

In-Memory Storage

Useful for testing. Data persists only during application lifetime.

csharp
// Default instance
using var memory = VfsConnection.Create(
    VfsProviderType.Memory,
    "memory://"
);

// Named instance (useful for test isolation)
using var memory = VfsConnection.Create(
    VfsProviderType.Memory,
    "memory://name=test-instance"
);

TIP

Named instances share storage across connections with the same name. Use unique names for test isolation.

MinIO

MinIO is an S3-compatible object storage server:

csharp
using var minio = VfsConnection.Create(
    VfsProviderType.Minio,
    "minio://endpoint=localhost:9000;accessKey=minioadmin;secretKey=minioadmin;bucket=my-bucket"
);

Connection String Parameters

ParameterDescriptionRequired
endpointMinIO server endpointYes
accessKeyAccess keyYes
secretKeySecret keyYes
bucketBucket nameYes
secureUse HTTPS (default: false)No

Backblaze B2

csharp
using var b2 = VfsConnection.Create(
    VfsProviderType.B2,
    "b2://keyId=...;applicationKey=...;bucketId=..."
);

SFTP

csharp
using var sftp = VfsConnection.Create(
    VfsProviderType.SFTP,
    "sftp://host=sftp.example.com;port=22;username=user;password=pass;path=/uploads"
);

Connection String Parameters

ParameterDescriptionRequired
hostSFTP server hostnameYes
portSFTP port (default: 22)No
usernameUsernameYes
passwordPasswordYes*
pathBase path on serverNo

VFS Operations

All providers support the same operations via extension methods:

Upload Files

csharp
using MJCZone.MediaMatic;

// Upload a file
using var stream = File.OpenRead("photo.jpg");
await vfs.UploadFileAsync(stream, "images/photo.jpg");

// Upload with overwrite
await vfs.UploadFileAsync(stream, "images/photo.jpg", overwrite: true);

// Upload an image with processing
var result = await vfs.UploadImageAsync(stream, "images/photo.jpg", new ImageUploadOptions
{
    GenerateThumbnails = true,
    ThumbnailSizes = [320, 640, 1024],
    GenerateFormats = true,
    Formats = [ImageFormat.WebP],
});

Download Files

csharp
// Download to stream
using var stream = await vfs.DownloadAsync("images/photo.jpg");

// Copy to file
using var fileStream = File.Create("downloaded.jpg");
await stream.CopyToAsync(fileStream);

List Files and Folders

csharp
// List files in a folder
var files = await vfs.ListFilesAsync("images/");

// List folders
var folders = await vfs.ListFoldersAsync("images/");

Create Folders

csharp
// Create a folder
await vfs.CreateFolderAsync("images/gallery/");

// Create nested folders (creates parent folders if needed)
await vfs.CreateFolderAsync("uploads/2025/01/photos/");

Delete Files and Folders

csharp
// Delete a file
await vfs.DeleteAsync("images/photo.jpg");

// Delete a folder and all contents
await vfs.DeleteFolderAsync("images/gallery/");

Check Existence

csharp
var exists = await vfs.ExistsAsync("images/photo.jpg");

Get Metadata

csharp
var metadata = await vfs.GetMetadataAsync("images/photo.jpg");
Console.WriteLine($"MIME Type: {metadata.MimeType}");
Console.WriteLine($"Dimensions: {metadata.Width}x{metadata.Height}");

Process Images

csharp
// Resize an image
var result = await vfs.ProcessImageAsync(
    "images/photo.jpg",
    "images/photo_thumb.jpg",
    new ImageProcessingOptions
    {
        Width = 300,
        Format = ImageFormat.WebP,
        Quality = 80,
    }
);

Testing with Testcontainers

MediaMatic includes test fixtures for Testcontainers:

LocalStack (S3)

csharp
await using var localstack = new LocalStackBuilder()
    .WithImage("localstack/localstack:latest")
    .Build();

await localstack.StartAsync();

using var s3 = VfsConnection.Create(
    VfsProviderType.S3,
    $"s3://keyId=test;key=test;bucket=test;region=us-east-1;serviceUrl={localstack.GetConnectionString()}"
);

MinIO Container

csharp
await using var minio = new MinioBuilder()
    .WithImage("minio/minio:latest")
    .Build();

await minio.StartAsync();

using var vfs = VfsConnection.Create(
    VfsProviderType.Minio,
    $"minio://endpoint={minio.GetConnectionString()};accessKey=minioadmin;secretKey=minioadmin;bucket=test"
);

Best Practices

Environment-Based Configuration

csharp
var provider = Enum.Parse<VfsProviderType>(
    builder.Configuration["Storage:Provider"] ?? "Local"
);
var connectionString = builder.Configuration["Storage:ConnectionString"]!;

using var vfs = VfsConnection.Create(provider, connectionString);
json
{
  "Storage": {
    "Provider": "S3",
    "ConnectionString": "s3://keyId=...;key=...;bucket=...;region=..."
  }
}

ASP.NET Core Integration

For web applications, use the MediaMatic ASP.NET Core package with filesources:

csharp
builder.Services.AddMediaMatic(options =>
{
    options.UseInMemoryFilesourceRepository();
});

// Configure filesources via REST API or programmatically

Error Handling

csharp
try
{
    await vfs.UploadFileAsync(stream, path);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("already exists"))
{
    logger.LogWarning("File already exists at {Path}", path);
}
catch (KeyNotFoundException ex)
{
    logger.LogError("File not found: {Path}", path);
}

Next Steps