File Storage

Strategy pattern with 4 providers (Local, Azure Blob, AWS S3, MinIO) with tenant-scoped directories.

SCRIPE uses the Strategy pattern for file storage, allowing seamless switching between local filesystem, Azure Blob Storage, AWS S3, and MinIO. All storage is tenant-scoped with configurable directories.

Storage Architecture

File Storage Architecture (Strategy Pattern)
LocalFileStorage — wwwroot/ filesystem
AzureBlobStorage — Azure Blob Containers
AwsS3Storage — AWS S3 Buckets
MinIOStorage — Self-hosted S3-compatible
implements
IFileStorageService — Abstraction interface

IFileStorageService Interface

IFileStorageService — ContractC#
public interface IFileStorageService
{
    Task<string> UploadAsync(Stream stream, string fileName,
        string folder, CancellationToken ct = default);

    Task<Stream?> DownloadAsync(string path,
        CancellationToken ct = default);

    Task<bool> DeleteAsync(string path,
        CancellationToken ct = default);

    Task<bool> ExistsAsync(string path,
        CancellationToken ct = default);

    Task<FileMetadata> GetMetadataAsync(string path,
        CancellationToken ct = default);

    string GetPublicUrl(string path);
}

Storage Provider Implementations

appsettings.json — LocalJSON
{
  "FileStorage": {
    "Provider": "Local",
    "Local": {
      "BasePath": "wwwroot/uploads",
      "RequestPath": "/uploads",
      "MaxFileSizeMB": 10,
      "AllowedExtensions": [".jpg", ".png", ".pdf", ".docx"]
    }
  }
}

File Upload & Processing Pipeline

Upload Flow with ValidationC#
// In Controller
[HttpPost("upload")]
[RequestSizeLimit(10_000_000)] // 10 MB
public async Task<IActionResult> Upload(IFormFile file)
{
    // 1. Validate file
    var validation = _fileValidator.Validate(file);
    if (!validation.IsValid)
        return BadRequest(validation.Errors);

    // 2. Generate safe filename
    var safeFileName = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";

    // 3. Upload via storage service
    var path = await _storage.UploadAsync(
        file.OpenReadStream(),
        safeFileName,
        "avatars", // folder
        ct
    );

    // 4. Return public URL
    return Ok(new { url = _storage.GetPublicUrl(path) });
}

File Validation

ValidationRuleError Message
File sizeMax 10 MB (configurable)File exceeds maximum size
Image dimensionsMax 4096×4096 pxImage dimensions too large
Extension whitelist.jpg, .png, .gif, .webp, .pdf, .docxFile type not allowed
MIME type checkVerify MIME matches extensionFile content doesn't match extension
Magic bytesCheck file header bytesCorrupted or fake file detected
Filename sanitizationRemove special chars, limit lengthApplied automatically