Подключение MinIO (S3-совместимое хранилище) в ASP.NET Core
Иван Гурин
Технологии интеграции информационных систем
6 мин
S3 (Simple Storage Service) - это объектное хранилище для хранения и отдачи файлов по HTTP API. В отличие от хранения файлов в файловой системе сервера, S3-подход:
- не привязан к конкретному инстансу приложения;
- масштабируется горизонтально;
- корректно работает в Docker и Kubernetes;
- отделяет хранение файлов от бизнес-логики.
MinIO - это self-hosted S3-совместимое хранилище. Оно реализует API, совместимое с Amazon S3, но может быть запущено локально или в приватном облаке.
Где используется S3
Типовые сценарии:
- пользовательские загрузки (файлы, документы, аватары);
- хранение больших бинарных объектов;
- раздача файлов без проксирования через backend;
- резервное копирование;
- временные и технические файлы.
Архитектура примера
Поток данных:
[HTTP Client]
|
v
[ASP.NET Core API]
|
v
[MinIO (S3 API)]
|
v
[Bucket / Objects]
- API принимает файл через multipart/form-data
- сервис сохраняет файл в MinIO
- по запросу файл возвращается клиенту
Практический пример
Установка пакетов
Добавьте NuGet-пакет (через консоль диспетчера пакетов):
Install-Package Minio
Сервис работы с файлами FileStorageService
using Minio;
using Minio.DataModel.Args;
public class FileStorageService
{
private readonly IMinioClient _minio;
public FileStorageService(IMinioClient minio)
{
_minio = minio;
}
public async Task UploadAsync(string objectName, string bucket, Stream content, string contentType)
{
var exists = await _minio.BucketExistsAsync(
new BucketExistsArgs().WithBucket(bucket));
if (!exists)
{
await _minio.MakeBucketAsync(
new MakeBucketArgs().WithBucket(bucket));
}
await _minio.PutObjectAsync(
new PutObjectArgs()
.WithBucket(bucket)
.WithObject(objectName)
.WithStreamData(content)
.WithObjectSize(content.Length)
.WithContentType(contentType));
}
public async Task<Stream> DownloadAsync(string objectName, string bucket)
{
var memory = new MemoryStream();
await _minio.GetObjectAsync(
new GetObjectArgs()
.WithBucket(bucket)
.WithObject(objectName)
.WithCallbackStream(stream =>
{
stream.CopyTo(memory);
}));
memory.Position = 0;
return memory;
}
}
Регистрация в DI
builder.Services.AddSingleton(_ =>
{
return new MinioClient()
.WithEndpoint("localhost:9000")
.WithCredentials("minio_access_key", "minio_secret_key")
.WithSSL(false) // только для локальной разработки
.Build();
});
builder.Services.AddScoped<FileStorageService>();
Контроллер FilesController
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/files")]
public class FilesController : ControllerBase
{
private readonly FileStorageService _storage;
public FilesController(FileStorageService storage)
{
_storage = storage;
}
[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("File is empty");
await using var stream = file.OpenReadStream();
await _storage.UploadAsync(
file.FileName,
"files",
stream,
file.ContentType);
return Ok(new { file = file.FileName });
}
[HttpGet("download/{name}")]
public async Task<IActionResult> Download(string name)
{
var stream = await _storage.DownloadAsync(name, "files");
return File(
stream,
"application/octet-stream",
name);
}
}
docker-compose.yml для MinIO
services:
minio-s3:
image: minio/minio
container_name: minio-s3
hostname: minio-s3
restart: always
ports:
- "9000:9000"
- "9001:9001"
volumes:
- ./storage:/data
environment:
MINIO_ACCESS_KEY: minio_access_key
MINIO_SECRET_KEY: minio_secret_key
command: server /data --console-address ":9001"
Проверка работы
Запустить MinIO:
docker-compose up -dЗапустить ASP.NET Core приложение
Загрузить файл:
curl --location 'http://localhost/api/files/upload' --form 'file=@"file.png"'Скачать файл:
curl --location 'http://localhost/api/files/download/file.png'
Методические ремарки
Упрощения
- bucket создаётся при первом запросе;
- файл читается в память при скачивании;
- отсутствуют таймауты.
Для production
- использовать streaming вместо MemoryStream;
- ограничить размер файлов;
- использовать presigned URLs;
- вынести секреты в переменные окружения;
- добавить логирование и политику повторов.
Заключение
MinIO позволяет использовать S3-подход без привязки к облачному провайдеру. Пример демонстрирует минимальную, но рабочую интеграцию с ASP.NET Core и может служить базой для production-решения.