S3

Dosaic.Plugins.Persistence.S3 is a plugin that provides S3-compatible object storage for Dosaic applications. It wraps the Minioarrow-up-right client, adds automatic MIME-type detection via Mime-Detectivearrow-up-right, bucket-prefixing, SHA-256 hashing, OpenTelemetry tracing, and a local-filesystem fallback for development and testing.

Installation

dotnet add package Dosaic.Plugins.Persistence.S3

or add as a package reference to your .csproj:

<PackageReference Include="Dosaic.Plugins.Persistence.S3" Version=""/>

Configuration

appsettings.yml

s3:
  endpoint: "s3.example.com"         # S3 / MinIO endpoint (host[:port])
  accessKey: "your-access-key"
  secretKey: "your-secret-key"
  region: "us-east-1"                # optional
  useSsl: true                       # optional, default false
  bucketPrefix: "myapp-"             # optional, prefixed to every bucket name
  healthCheckPath: ""                # optional, path appended to endpoint URL for readiness check
  useLocalFileSystem: false          # optional, use local filesystem instead of S3 (dev/test mode)
  localFileSystemPath: "./nodep-s3"  # optional, root path used when useLocalFileSystem is true

When useLocalFileSystem: true the plugin stores files on the local disk at localFileSystemPath instead of connecting to an S3 endpoint. This is useful for local development and integration tests where no MinIO/S3 instance is available.

Registration and Configuration

The plugin is automatically discovered and registered by the Dosaic source generator when using PluginWebHostBuilder. No manual registration is required in that case.

Define an enum whose values are annotated with [FileBucket]. The attribute declares the bucket name and the allowed FileType for validation:

Then register IFileStorage<MyBucket> in DI:

IFileStorage<MyBucket> can then be injected anywhere in your application.

Untyped bucket storage

The plugin also registers an untyped IFileStorage. Because there is no enum to inspect, no bucket migration service exists for this interface — you must create buckets manually at runtime:

Manual registration without Dosaic WebHost

Usage

Creating a BlobFile

BlobFile<TBucket> carries the file metadata and the target bucket/key. Use the fluent helpers to attach filename or extension metadata:

Upload a file

Download file metadata

Stream file content

Delete a file

Compute a SHA-256 hash

Both IFileStorage and IFileStorage<TBucket> implement IComputeHash. The hash is also stored automatically in BlobFileMetaData.Hash when a file is uploaded.

Custom MIME-type definitions

Override IFileTypeDefinitionResolver

Implement IFileTypeDefinitionResolver and register it to replace the default definitions:

The built-in implementation is DefaultFileTypeDefinitionResolver, which delegates to MimeDetective.Definitions.DefaultDefinitions.

Override IContentInspector

The content inspector is used for binary MIME detection when no file extension is available:

MIME type detection and validation

When BlobFileMetaData.ContentType is not set on a BlobFile, the plugin detects it automatically in this order:

  1. If BlobFileMetaData.FileExtension is set → look up via IFileTypeDefinitionResolver.

  2. Otherwise → pass the stream bytes through IContentInspector.

  3. If still unresolved → fall back to application/octet-stream.

After detection, the content-type is validated against the FileType declared on the [FileBucket] attribute. If they do not match, a ValidationDosaicException is thrown. Use FileType.Any to skip validation entirely.

Metadata keys (BlobFileMetaData)

Constant
Key
Description

BlobFileMetaData.Filename

original-filename

Original file name

BlobFileMetaData.FileExtension

original-file-extension

File extension (e.g. .pdf)

BlobFileMetaData.ContentType

content-type

MIME type

BlobFileMetaData.ContentLength

content-length

File size in bytes

BlobFileMetaData.ETag

etag

S3 ETag (quoted)

BlobFileMetaData.Hash

hash

SHA-256 hex digest (auto-computed on upload)

FileId encoding

FileId and FileId<TBucket> encode the bucket name and object key as a single Sqidsarrow-up-right-encoded string accessible via the .Id property. This opaque identifier is safe to expose in URLs and query strings.

Permission-guarded service wrapper

Example of wrapping the storage interface with permission checks:

Example: file download controller

Features

  • S3-compatible storage via the Minio .NET client (works with AWS S3, MinIO, Wasabi, etc.)

  • Local filesystem fallback (useLocalFileSystem: true) for zero-dependency dev/test environments

  • Typed enum-based buckets with IFileStorage<TBucket> and per-bucket FileType validation

  • Untyped bucket storage with IFileStorage and runtime CreateBucketAsync

  • Automatic MIME detection from file extension or stream content via Mime-Detective

  • Automatic SHA-256 hashing stored as object metadata on upload

  • Bucket prefix support to namespace all buckets per environment

  • Automatic bucket migration via BlobStorageBucketMigrationService<T> (hosted background service with retry)

  • Opaque file IDs using Sqids encoding (bucket + key → single URL-safe string)

  • OpenTelemetry tracing on all storage operations via DosaicDiagnostic

  • Readiness health check — URL probe for S3 or filesystem write-test for local mode

  • Replaceable IFileTypeDefinitionResolver and IContentInspector for custom MIME handling

Last updated