Synergy.FileStorage
1.0.0
See the version list below for details.
dotnet add package Synergy.FileStorage --version 1.0.0
NuGet\Install-Package Synergy.FileStorage -Version 1.0.0
<PackageReference Include="Synergy.FileStorage" Version="1.0.0" />
<PackageVersion Include="Synergy.FileStorage" Version="1.0.0" />
<PackageReference Include="Synergy.FileStorage" />
paket add Synergy.FileStorage --version 1.0.0
#r "nuget: Synergy.FileStorage, 1.0.0"
#:package Synergy.FileStorage@1.0.0
#addin nuget:?package=Synergy.FileStorage&version=1.0.0
#tool nuget:?package=Synergy.FileStorage&version=1.0.0
Synergy.FileStorage
A robust file storage service library for Synergy applications, providing seamless integration with MinIO for object storage and Marten for metadata management.
Features
- 📁 File Upload: Upload files via Stream or IFormFile with automatic bucket creation
- 📥 File Download: Download files with or without metadata (content type, filename)
- 🗑️ File Management: Delete files and check file existence
- 📊 Metadata Storage: Store file metadata using Marten document database
- 🔄 Async Operations: All operations are fully asynchronous
- 🪣 Auto Bucket Creation: Automatically creates MinIO buckets if they don't exist
- 🏷️ Rich Metadata: Stores file name, content type, uploader information, and more
Installation
Install the package via NuGet:
dotnet add package Synergy.FileStorage
Or via Package Manager:
Install-Package Synergy.FileStorage
Prerequisites
- .NET 8.0 or later
- MinIO server (or compatible S3-compatible storage)
- PostgreSQL database (for Marten metadata storage)
Dependencies
- Minio (7.0.0) - S3-compatible object storage client
- Marten (8.17.0) - Document database for PostgreSQL
- MediatR (12.2.0) - Mediator pattern implementation
- MassTransit.AspNetCore (7.3.1) - Message bus integration
Quick Start
1. Configure MinIO Client
using Minio;
var minioClient = new MinioClient()
.WithEndpoint("localhost:9000")
.WithCredentials("minioadmin", "minioadmin")
.Build();
2. Register Services
using Synergy.FileStorage.Services;
// Register MinIO client
services.AddSingleton<IMinioClient>(minioClient);
// Register FileStorageService
services.AddScoped<IFileStorageService>(provider =>
{
var minioClient = provider.GetRequiredService<IMinioClient>();
return new FileStorageService(minioClient, "my-bucket-name");
});
3. Use the Service
using Synergy.FileStorage.Services;
public class MyController : ControllerBase
{
private readonly IFileStorageService _fileStorageService;
public MyController(IFileStorageService fileStorageService)
{
_fileStorageService = fileStorageService;
}
[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
var fileId = await _fileStorageService.UploadFormFileAsync(
file,
file.FileName,
file.ContentType,
file.Length,
Guid.Parse("user-id-here")
);
return Ok(new { FileId = fileId });
}
[HttpGet("download/{fileId}")]
public async Task<IActionResult> DownloadFile(Guid fileId)
{
var (stream, contentType, fileName) = await _fileStorageService
.DownloadFileWithMetadataAsync(fileId);
return File(stream, contentType, fileName);
}
}
API Reference
IFileStorageService
UploadFileAsync
Uploads a file from a Stream.
Task<Guid> UploadFileAsync(
Stream fileStream,
string fileName,
string contentType,
long contentLength,
Guid uploadedBy,
CancellationToken cancellationToken = default
)
Returns: The unique identifier (Guid) of the uploaded file.
UploadFormFileAsync
Uploads a file from an IFormFile (ASP.NET Core).
Task<Guid> UploadFormFileAsync(
IFormFile formFile,
string fileName,
string contentType,
long contentLength,
Guid uploadedBy,
CancellationToken cancellationToken = default
)
Returns: The unique identifier (Guid) of the uploaded file.
DownloadFileAsync
Downloads a file as a Stream.
Task<Stream> DownloadFileAsync(
Guid fileId,
CancellationToken cancellationToken = default
)
Returns: A Stream containing the file data.
DownloadFileWithMetadataAsync
Downloads a file with its metadata (content type and filename).
Task<(Stream Stream, string ContentType, string? FileName)> DownloadFileWithMetadataAsync(
Guid fileId,
CancellationToken cancellationToken = default
)
Returns: A tuple containing the file stream, content type, and filename.
DeleteFileAsync
Deletes a file from storage.
Task DeleteFileAsync(
string objectName,
CancellationToken cancellationToken = default
)
FileExistsAsync
Checks if a file exists in storage.
Task<bool> FileExistsAsync(
string objectName,
CancellationToken cancellationToken = default
)
Returns: true if the file exists, false otherwise.
IFileRepository
Repository interface for managing file metadata using Marten.
Task<File?> GetByIdAsync(Guid fileId, CancellationToken cancellationToken = default);
Task SaveAsync(File file, CancellationToken cancellationToken = default);
Task<IEnumerable<File>> GetAllAsync(CancellationToken cancellationToken = default);
File Model
public record File
{
public Guid Id { get; init; }
public string FileName { get; init; }
public string ContentType { get; init; }
public long FileSize { get; init; }
public DateTime UploadedAt { get; init; }
public bool IsDeleted { get; init; }
}
Configuration
MinIO Configuration
Ensure your MinIO server is running and accessible. The service will automatically create the specified bucket if it doesn't exist.
Bucket Name
The bucket name is provided during service registration. Choose a meaningful name for your application:
new FileStorageService(minioClient, "my-application-files")
Best Practices
- Error Handling: Always wrap file operations in try-catch blocks
- Stream Disposal: Ensure streams are properly disposed after use
- Bucket Naming: Use descriptive bucket names that match your application's purpose
- User Tracking: Always provide valid user IDs when uploading files for audit purposes
- Content Type: Always specify the correct content type for proper file handling
Example: Complete File Upload/Download Flow
public class FileController : ControllerBase
{
private readonly IFileStorageService _fileStorageService;
private readonly IFileRepository _fileRepository;
public FileController(
IFileStorageService fileStorageService,
IFileRepository fileRepository)
{
_fileStorageService = fileStorageService;
_fileRepository = fileRepository;
}
[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file, Guid userId)
{
try
{
// Upload to MinIO
var fileId = await _fileStorageService.UploadFormFileAsync(
file, file.FileName, file.ContentType, file.Length, userId);
// Save metadata to database
var fileRecord = new Synergy.FileStorage.DTOs.File
{
Id = fileId,
FileName = file.FileName,
ContentType = file.ContentType,
FileSize = file.Length,
UploadedAt = DateTime.UtcNow,
IsDeleted = false
};
await _fileRepository.SaveAsync(fileRecord);
return Ok(new { FileId = fileId });
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
[HttpGet("{fileId}")]
public async Task<IActionResult> Download(Guid fileId)
{
try
{
// Get metadata
var fileRecord = await _fileRepository.GetByIdAsync(fileId);
if (fileRecord == null || fileRecord.IsDeleted)
return NotFound();
// Download file
var (stream, contentType, fileName) = await _fileStorageService
.DownloadFileWithMetadataAsync(fileId);
return File(stream, contentType, fileName ?? fileRecord.FileName);
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
}
License
This project is licensed under the MIT License.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues, questions, or contributions, please visit:
Version History
- 1.0.0 - Initial release with file upload, download, and management capabilities
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Marten (>= 8.17.0)
- MassTransit.AspNetCore (>= 7.3.1)
- MediatR (>= 12.2.0)
- Minio (>= 7.0.0)
- Swashbuckle.AspNetCore (>= 6.6.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.