Skip to content

File Storage

SimpleModule provides a file storage abstraction with pluggable providers for local filesystem, AWS S3, and Azure Blob Storage. The FileStorage module adds HTTP endpoints, database tracking, and an admin UI on top of this abstraction.

Storage Providers

IStorageProvider Interface

All providers implement a common interface:

csharp
public interface IStorageProvider
{
    Task<StorageResult> SaveAsync(string path, Stream content, string contentType);
    Task<Stream?> GetAsync(string path);
    Task<bool> DeleteAsync(string path);
    Task<bool> ExistsAsync(string path);
    Task<IReadOnlyList<StorageEntry>> ListAsync(string prefix);
}

Local Storage

Stores files on the local filesystem. Best for development and single-server deployments.

csharp
builder.Services.AddLocalStorage(builder.Configuration);
json
{
  "Storage": {
    "Provider": "Local",
    "Local": {
      "BasePath": "./storage"
    }
  }
}

AWS S3

csharp
builder.Services.AddS3Storage(builder.Configuration);
json
{
  "Storage": {
    "Provider": "S3",
    "S3": {
      "BucketName": "my-bucket",
      "AccessKey": "your-access-key",
      "SecretKey": "your-secret-key",
      "Region": "us-east-1",
      "ServiceUrl": "",
      "ForcePathStyle": false
    }
  }
}

Set ServiceUrl for S3-compatible services (MinIO, DigitalOcean Spaces). Set ForcePathStyle to true for path-style URL access.

Azure Blob Storage

csharp
builder.Services.AddAzureBlobStorage(builder.Configuration);
json
{
  "Storage": {
    "Provider": "Azure",
    "Azure": {
      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=...",
      "ContainerName": "files"
    }
  }
}

FileStorage Module

The FileStorage module provides HTTP endpoints and a database-backed file registry on top of the storage abstraction.

API Endpoints

MethodRoutePermissionDescription
POST/api/files/FileStorage.UploadUpload a file (multipart form)
GET/api/files/FileStorage.ViewList files (optional ?folder= filter)
GET/api/files/{id}FileStorage.ViewGet file metadata by ID
GET/api/files/{id}/downloadFileStorage.ViewDownload file content
DELETE/api/files/{id}FileStorage.DeleteDelete a file
GET/api/files/foldersFileStorage.ViewList folders (optional ?parent= filter)

Browse UI

A file browser view at /files/browse lets users navigate folders, upload files, and download or delete existing files.

Module Settings

SettingDefaultDescription
FileStorage.MaxFileSizeMb50Maximum upload size in megabytes
FileStorage.AllowedExtensions.jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.zipComma-separated allowed file extensions

Using from Other Modules

Inject IFileStorageContracts to interact with file storage from any module:

csharp
public interface IFileStorageContracts
{
    Task<IEnumerable<StoredFile>> GetFilesAsync(string? folder = null);
    Task<StoredFile?> GetFileByIdAsync(FileStorageId id);
    Task<StoredFile> UploadFileAsync(
        Stream content, string fileName, string contentType, string? folder = null);
    Task DeleteFileAsync(FileStorageId id);
    Task<Stream?> DownloadFileAsync(FileStorageId id);
    Task<IEnumerable<string>> GetFoldersAsync(string? parentFolder = null);
}

Provider Comparison

FeatureLocalS3Azure
External dependenciesNoneAWSSDK.S3Azure.Storage.Blobs
Folder supportPhysical directoriesPrefix-basedPrefix-based
PaginationN/AListObjectsV2GetBlobsByHierarchyAsync
Best forDevelopment, single serverProduction, multi-regionProduction, Azure ecosystem

Path Handling

All paths are normalized to forward slashes internally. The StoragePathHelper utility provides safe path operations:

  • Path traversal attacks are blocked (paths cannot escape the base directory)
  • Leading/trailing slashes are normalized
  • File names and folder names are extracted consistently across providers

Next Steps

Released under the MIT License.