При разработке веб-приложений в первую очередь нужно решить, где будут храниться файлы, с которыми работает приложение. В традиционных веб-приложениях файлы обычно размещаются на сервере, который обслуживает приложение. Однако этот метод имеет свои ограничения: сложно эффективно управлять большим количеством данных и обеспечить их безопасность. Более современным и удобным решением является использование облачного хранилища, которое позволяет легко сохранять и получать файлы через интернет. Одним из вариантов облачного хранилища является объектное хранилище S3.
Объектное хранилище — это тип хранения данных, где информация сохраняется как отдельные объекты, что позволяет эффективно управлять большими объемами данных. В нашем случае объекты — это файлы, которые мы будем загружать и скачивать с облака. В этой статье мы покажем, как настроить S3-хранилище Timeweb Cloud и подключить его к вашему веб-приложению.
Наш проект разрабатывается на .NET 9 — одной из самых последних версий фреймворка от Microsoft. Эта платформа обеспечивает высокую производительность веб-приложений, особенно при использовании ASP.NET, что позволяет эффективно обрабатывать пользовательские запросы через интернет.
В этой статье мы рассмотрим следующие ключевые этапы настройки нашего проекта:
-
Создание проекта в Timeweb Cloud — создадим проект и объектное хранилище в Timeweb Cloud и настроим его для хранения наших файлов.
-
Развертывание ASP.NET-проекта — создадим веб-приложение на ASP.NET и подготовим его для работы, настроив все необходимые компоненты для обработки запросов.
-
Установка необходимых NuGet-пакетов — NuGet — это система для управления библиотеками и пакетами в .NET. Мы подключим библиотеки, которые помогут работать с S3-хранилищем, чтобы мы могли загружать и скачивать файлы.
-
Добавление поддержки Scalar — подключим поддержку OpenAPI с помощью Scalar, чтобы упростить тестирование нашего API (интерфейса для взаимодействия с приложением).
-
Настройка переменных окружения — для надежного хранения ключей доступа к S3-хранилищу настроим переменные окружения, чтобы хранить конфиденциальную информацию в безопасном месте, а не прямо в коде.
-
Создание минимального Docker-контейнера — Docker — это инструмент, который позволяет упаковать приложение в контейнер, что упрощает его развертывание на разных серверах. Мы создадим контейнер, чтобы проще развернуть наше приложение в облаке.
-
Подключение к S3 API — научимся работать с S3 API, чтобы загружать и скачивать файлы.
-
Разработка контроллеров — добавим эндпоинты (адреса, по которым приложение будет получать запросы) для работы с хранилищем, чтобы пользователи могли загружать и скачивать файлы через интернет.
Весь процесс будет пошаговым, и в конце вы получите работающий API, который будет взаимодействовать с облачным хранилищем S3, позволяя загружать и скачивать файлы.
Объектное S3-хранилище
совместимое с протоколом Amazon S3.
Шаг 1. Создание проекта в Timeweb Cloud
-
Перейдите в панель управления Timeweb Cloud и создайте новый проект.

-
В панели управления создайте S3-хранилище. Выберите подходящий тариф (для тестового развертывания достаточно минимального конфигурации) и перейдите в бакет — контейнер для хранения объектов.

- Перейдите в сам бакет, чтобы просмотреть его конфигурацию. Он будет доступен внутри вашего проекта или в разделе «Хранилище S3».

-
Сохраните три ключевых значения:
-
- Название бакета
- S3 Access Key
- S3 Secret Access Key

Шаг 2. Развертывание ASP.NET-проекта
Выполнение этого и следующих шагов также представлено на скринкасте.
Откройте консоль и создайте директорию для проекта:
mkdir timeweb-s3-api
Затем перейдите в эту директорию:
cd timeweb-s3-api
Инициализируйте проект командой:
dotnet new webapi
Проект будет создан с версией .NET 9. Чтобы убедиться в этом, откройте файл с расширением .csproj и найдите строку:
<TargetFramework>net9.0</TargetFramework>
Для минимальной конфигурации файл Program.cs должен выглядеть так:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenApi(); var app = builder.Build(); app.MapOpenApi(); app.Run();
Шаг 3. Установка NuGet-пакетов
Для работы с S3 и нужными библиотеками установите необходимые пакеты, поочередно выполнив следующие команды:
dotnet add package AWSSDK.Extensions.NETCore.Setup --version 4.0.0-preview dotnet add package AWSSDK.S3 --version 4.0.0-preview dotnet add package DotNetEnv --version 3.1.1 dotnet add package Microsoft.AspNetCore.OpenApi --version 9.0.2 dotnet add package Scalar.AspNetCore --version 2.0.25
После установки пакетов дождитесь их загрузки и подтвердите установку последнего пакета, снова нажав Enter.
Затем соберите проект, выполнив команду:
dotnet build
Шаг 4. Добавление файла GlobalUsings.cs
Создайте файл GlobalUsings.cs в корне проекта и добавьте в него следующие пространства имен:
global using Scalar.AspNetCore; global using DotNetEnv; global using Amazon.S3; global using Microsoft.Extensions.Options; global using Microsoft.AspNetCore.Mvc; global using Amazon.S3.Model; global using System.Net;
Этот файл позволит избежать дублирования директив using в каждом файле проекта, обеспечивая доступ к необходимым библиотекам везде, где это потребуется.
Шаг 5. Добавление Scalar для поддержки API
Добавьте поддержку Scalar API, чтобы упростить тестирование приложения.
Для этого откройте Program.cs и сразу после строки var app = builder.Build(); добавьте:
app.MapScalarApiReference();
Это создаст страницу http://localhost/scalar, где веб-клиент сможет видеть доступные API-эндпоинты — адреса, по которым можно отправлять запросы.
Шаг 6. Настройка переменных окружения
Создайте файл .env в корневой папке проекта. В этом файле будут храниться переменные окружения — настройки, которые приложение будет использовать при работе.
Замените значения в скобках на свои данные для подключения к бакету.
Пример содержимого файла:
AWS_BUCKET_NAME=[Название бакета] AWS_ACCESS_KEY=[S3 Access Key] AWS_SECRET_ACCESS_KEY=[S3 Secret Access Key] AWS_SERVICE_URL=https://s3.twcstorage.ru ASPNETCORE_URLS=http://+:80
В итоге файл будет выглядеть подобным образом:

Добавьте в проект переменные окружения. Для этого откройте Program.cs и вставьте следующий код сразу после строки var builder = WebApplication.CreateBuilder(args):
Env.Load(); builder.Configuration.AddEnvironmentVariables();
Шаг 7. Создание Docker-контейнера
Создайте Dockerfile в корневой папке проекта. Этот файл нужен, чтобы Docker мог собрать образ — упакованную версию приложения со всеми зависимостями, готовую для запуска в любой среде.
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app EXPOSE 80 COPY . . RUN dotnet restore timeweb-s3-api.csproj RUN dotnet publish timeweb-s3-api.csproj -c Release -o /app/publish FROM mcr.microsoft.com/dotnet/aspnet:9.0 WORKDIR /app COPY --from=build /app/publish . ENTRYPOINT ["dotnet", "timeweb-s3-api.dll"]
Добавьте файл docker-compose.yml со следующим содержимым:
services:
backend:
container_name: backend
build:
context: .
dockerfile: Dockerfile
env_file:
- .env
ports:
- 80:80
networks:
- app-network
networks:
app-network:
driver: bridge
Шаг 8. Подключение к S3 API
Создайте файл S3Options.cs в корневой папке проекта. В нем будут храниться настройки для подключения к S3-хранилищу. Добавьте в него следующий код:
public class S3Options { public string AccessKey { get; set; } = null!; public string SecretKey { get; set; } = null!; public string ServiceUrl { get; set; } = null!; public string BucketName { get; set; } = null!; }
Далее для того, чтобы использовать настройки окружения в нашем приложении, в файл Program.cs после строки builder.Services.AddOpenApi(); добавьте код:
builder.Services.Configure<S3Options>(options => { options.AccessKey = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY") ?? ""; options.SecretKey = Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY") ?? ""; options.ServiceUrl = Environment.GetEnvironmentVariable("AWS_SERVICE_URL") ?? ""; options.BucketName = Environment.GetEnvironmentVariable("AWS_BUCKET_NAME") ?? ""; }); builder.Services.AddSingleton<IAmazonS3>(sp => { var options = sp.GetRequiredService<IOptions<S3Options>>().Value; return new AmazonS3Client(options.AccessKey, options.SecretKey, new AmazonS3Config { ServiceURL = options.ServiceUrl, ForcePathStyle = true }); });
Он нужен, чтобы передать настройки для работы с S3-хранилищем (например, ключи доступа и адрес сервиса) и сделать их доступными в приложении. Это называется «внедрение зависимостей» — способ передавать нужные параметры в разные части кода без их явного указания в каждом месте.
Шаг 9. Разработка контроллеров для работы с S3 в .NET 9
Для работы с объектным хранилищем S3 от Timeweb Cloud в проекте необходимо создать контроллер S3Controller. Он будет обрабатывать загрузку, получение и удаление изображений в S3.
Создание контроллера
В корневой директории создаем папку Controllers, а в ней — файл S3Controller.cs. Добавьте в него следующий код:
[ApiController] [Route("api/s3")] public class S3Controller : ControllerBase { private readonly S3Options _s3Options; private readonly IAmazonS3 _s3; public S3Controller(IOptions<S3Options> options, IAmazonS3 s3) { _s3Options = options.Value; _s3 = s3; } [HttpPost("image/{id}")] public async Task<ActionResult<PutObjectResponse>> Upload([FromRoute] int id, [FromForm(Name = "Data")] IFormFile file) { var request = new PutObjectRequest { BucketName = _s3Options.BucketName, Key = $"{id}", ContentType = file.ContentType, InputStream = file.OpenReadStream(), }; var response = await _s3.PutObjectAsync(request); return response.HttpStatusCode == HttpStatusCode.OK ? Ok(response) : BadRequest(); } [HttpGet("image/{id}")] public async Task<IActionResult> GetImage([FromRoute] int id) { var objectRequest = new GetObjectRequest { BucketName = _s3Options.BucketName, Key = $"{id}" }; var response = await _s3.GetObjectAsync(objectRequest); if (response.HttpStatusCode == HttpStatusCode.OK) return File(response.ResponseStream, response.Headers["Content-Type"]); return BadRequest(); } [HttpDelete("image/{id}")] public async Task<IActionResult> DeleteImage([FromRoute] int id) { var objectRequest = new DeleteObjectRequest { BucketName = _s3Options.BucketName, Key = $"{id}" }; var response = await _s3.DeleteObjectAsync(objectRequest); return response.HttpStatusCode == HttpStatusCode.NoContent ? NoContent() : BadRequest(); } }
Контроллер помечается атрибутами:
-
[ApiController]— указывает, что этот класс является контроллером API. -
[Route("api/s3")]— задает маршрут для запросов, начинающихся сapi/s3.
Также контроллер использует зависимости:
-
S3Options— объект конфигурации с настройками доступа к S3. -
IAmazonS3— клиент для взаимодействия с S3.
Они передаются через конструктор с внедрением зависимостей (IOptions<S3Options> для конфигурации и IAmazonS3 для работы с S3).
Разберем методы работы с файлами:
Метод [HttpPost("image/{id}")] используется для загрузки изображения в S3.
При вызове метода создается запрос PutObjectRequest, в котором указываются:
id— идентификатор файла (например, ID объекта в базе данных).IFormFile file— полученный файл изmultipart/form-data.
Входные параметры метода:
BucketName— название бакета,Key— имя файла в S3 (в данном случае переданный id),ContentType— тип файла,InputStream— поток загружаемого файла.
Запрос передается в PutObjectAsync, который выполняет загрузку. Если ответ OK (200), загрузка прошла успешно, иначе возвращается ошибка.
Метод [HttpGet("image/{id}")] позволяет получить изображение из S3.
При вызове метода создается запрос GetObjectRequest, в котором указываются:
BucketName— название бакета,Key— идентификатор файла.
Входной параметр метода:
id— идентификатор файла в S3.
Метод [HttpDelete("image/{id}")] удаляет изображение из S3.
При вызове метода создается запрос DeleteObjectRequest, содержащий:
BucketName— название бакета,Key— идентификатор файла.
Входной параметр метода:
id— идентификатор файла в S3.
После этого выполняется DeleteObjectAsync. Если статус ответа NoContent (204), файл успешно удален, иначе возвращается ошибка.
Добавление маршрутов в приложение
Чтобы контроллер начал работать, необходимо добавить в файле Program.cs после app.MapOpenApi(); следующие строки:
app.MapControllers(); app.UseRouting();
Этот метод регистрирует маршруты для всех контроллеров в приложении, включая S3Controller.
Также перед строкой var app = builder.Build(); добавьте:
builder.Services.AddControllers();
Вызов функции сообщает ASP.NET Core, что в приложении будут использоваться контроллеры и их нужно зарегистрировать. Без этого контроллеры не будут работать, даже если маршруты настроены.
Шаг 10. Тестирование с помощью Docker и Postman
Для тестирования нашего API, которое теперь доступно по адресу http://localhost, мы будем использовать два инструмента: Postman и Scalar. В обоих случаях мы будем отправлять HTTP-запросы на следующие эндпоинты:
- GET для получения файла по ID
- POST для загрузки файла
- DELETE для удаления файла
Эти запросы будут выполняться по шаблону http://localhost/api/s3/image/{id}, где {id} — это уникальный идентификатор изображения, с которым мы будем взаимодействовать.
Сначала необходимо запустить контейнер, чтобы приложение стало доступно. Для этого в терминале, находясь в директории проекта, выполните команду:
docker-compose up --build -d
Это создаст и запустит Docker-контейнер, собрав все необходимые компоненты приложения.
Тестирование с помощью Postman
Postman — это инструмент для тестирования API. Мы будем использовать его для отправки запросов на наш сервер.
Откройте Postman и введите URL запроса в формате http://localhost/api/s3/image/{id}, где {id} — это значение, которое вы хотите использовать для тестирования (например, 1).
Убедитесь, что запрос использует правильный HTTP-метод (GET, POST или DELETE).
Пример GET-запроса
URL: http://localhost/api/s3/image/1
Этот запрос будет пытаться получить файл с ID 1. Ответ будет содержать файл (если он существует) или сообщение об ошибке.
Пример POST-запроса (Загрузка файла)
URL: http://localhost/api/s3/image/1
В теле запроса:
- Тип данных:
form-data. - Ключ:
Data— сюда нужно добавить файл для загрузки.
Это запрос для загрузки изображения с ID 1 в хранилище S3. В form-data вы должны прикрепить файл, который хотите загрузить.
Пример DELETE-запроса (Удаление файла)
URL: http://localhost/api/s3/image/1
Этот запрос удаляет файл с ID 1 из S3-хранилища.
Пример из Postman продемонстрирован на картинке ниже.
Тестирование с помощью Scalar
Scalar — это инструмент для тестирования API с использованием OpenAPI, который подключен для удобства. Он позволяет увидеть список всех доступных эндпоинтов и взаимодействовать с ними прямо из браузера.
При использовании Scalar выполните следующие действия.
- Откройте браузер и перейдите по адресу:
http://localhost/scalar
Здесь отобразится список всех доступных эндпоинтов, включая /api/s3/image/{id} для работы с изображениями.
- В интерфейсе Scalar выберите нужный HTTP-метод (GET, POST или DELETE).
- Настройте запрос. Вы можете задать параметры запроса, например, указать id изображения, и отправить запрос непосредственно из Scalar
Примеры запросов в Scalar:
GET-запрос
URL: http://localhost/api/s3/image/1
Этот запрос пытается получить файл с ID 1. Если файл существует, Scalar вернет его с оригинальным Content-Type, иначе — сообщение об ошибке.
POST-запрос (Загрузка файла)
URL: http://localhost/api/s3/image/1
В теле запроса:
- Тип данных:
form-data - Ключ:
Data— здесь нужно прикрепить файл для загрузки
Этот запрос загружает изображение с ID 1 в хранилище S3.
DELETE-запрос
URL: http://localhost/api/s3/image/1
Этот запрос удаляет файл с ID 1 из S3-хранилища.
Пример из Scalar продемонстрирован на картинке ниже.

Тестирование через Postman и Scalar поможет убедиться, что все эндпоинты работают правильно и файлы могут быть загружены, получены и удалены с S3-хранилища.
Надежное облако для ваших проектов
477 ₽/мес
657 ₽/мес
Заключение
Мы успешно разработали и настроили приложение для работы с файлами в объектном хранилище S3 от Timeweb Cloud: создали хранилище, настроили проект на .NET 9, подключили необходимые библиотеки для работы с S3 и добавили поддержку Scalar. Мы также настроили переменные окружения и создали Docker-контейнер.
Теперь наше приложение позволяет загружать, получать и удалять файлы через API, взаимодействуя с объектным хранилищем S3, что делает его удобным и безопасным для использования в реальных проектах.
