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:
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.
builder.Services.AddLocalStorage(builder.Configuration);{
"Storage": {
"Provider": "Local",
"Local": {
"BasePath": "./storage"
}
}
}AWS S3
builder.Services.AddS3Storage(builder.Configuration);{
"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
builder.Services.AddAzureBlobStorage(builder.Configuration);{
"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
| Method | Route | Permission | Description |
|---|---|---|---|
POST | /api/files/ | FileStorage.Upload | Upload a file (multipart form) |
GET | /api/files/ | FileStorage.View | List files (optional ?folder= filter) |
GET | /api/files/{id} | FileStorage.View | Get file metadata by ID |
GET | /api/files/{id}/download | FileStorage.View | Download file content |
DELETE | /api/files/{id} | FileStorage.Delete | Delete a file |
GET | /api/files/folders | FileStorage.View | List 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
| Setting | Default | Description |
|---|---|---|
FileStorage.MaxFileSizeMb | 50 | Maximum upload size in megabytes |
FileStorage.AllowedExtensions | .jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.zip | Comma-separated allowed file extensions |
Using from Other Modules
Inject IFileStorageContracts to interact with file storage from any module:
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
| Feature | Local | S3 | Azure |
|---|---|---|---|
| External dependencies | None | AWSSDK.S3 | Azure.Storage.Blobs |
| Folder support | Physical directories | Prefix-based | Prefix-based |
| Pagination | N/A | ListObjectsV2 | GetBlobsByHierarchyAsync |
| Best for | Development, single server | Production, multi-region | Production, 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
- AI Agents -- using file storage with RAG knowledge indexing
- Configuration -- all storage configuration options
- Deployment -- production storage configuration