BrandUp.Extensions.ObjectStorage.Testing 1.0.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package BrandUp.Extensions.ObjectStorage.Testing --version 1.0.4
                    
NuGet\Install-Package BrandUp.Extensions.ObjectStorage.Testing -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BrandUp.Extensions.ObjectStorage.Testing" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BrandUp.Extensions.ObjectStorage.Testing" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="BrandUp.Extensions.ObjectStorage.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BrandUp.Extensions.ObjectStorage.Testing --version 1.0.4
                    
#r "nuget: BrandUp.Extensions.ObjectStorage.Testing, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BrandUp.Extensions.ObjectStorage.Testing@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BrandUp.Extensions.ObjectStorage.Testing&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=BrandUp.Extensions.ObjectStorage.Testing&version=1.0.4
                    
Install as a Cake Tool

BrandUp.Extensions.ObjectStorage

Библиотека для работы с S3-совместимыми объектными хранилищами (Yandex Cloud Object Storage, Amazon S3, MinIO и др.) через AWS SDK.

Пакеты

Пакет Описание
BrandUp.Extensions.ObjectStorage.Abstraction Интерфейсы и модели. Зависимостей от AWS SDK нет.
BrandUp.Extensions.ObjectStorage Реализация через AWSSDK.S3.
BrandUp.Extensions.ObjectStorage.Testing Фейковая in-memory реализация для тестов.

Быстрый старт

1. Описать метаданные объекта

public class UserPhotoMetadata : IObjectMetadata
{
    public string FileName { get; set; }
    public string ContentType { get; set; }
    public DateTime UploadedAt { get; set; }
}

Любой класс с публичным конструктором без параметров и публичными свойствами с геттером и сеттером.
Поддерживаемые типы свойств: string, int, bool, Guid, DateTime, decimal, enum и любые типы с TypeConverter. Значения null при сериализации пропускаются.

2. Зарегистрировать в DI

services.AddObjectStorage(opts =>
{
    opts.ServiceUrl           = "https://storage.yandexcloud.net";
    opts.AuthenticationRegion = "ru-central1";
    opts.AccessKeyId          = "...";
    opts.SecretAccessKey      = "...";
})
.AddMapping<UserPhotoMetadata>("my-bucket/photos");

Формат destination в AddMapping: bucketName или bucketName/prefix. Допустимые символы: буквы, цифры и /.

3. Использовать

// Через IObjectStorage (совместимый фасад)
public class PhotoService(IObjectStorage storage)
{
    public Task UploadAsync(Guid id, Stream photo)
        => storage.UploadAsync(id, new UserPhotoMetadata { FileName = "photo.jpg" }, photo);

    public Task<Stream?> DownloadAsync(Guid id)
        => storage.ReadAsync<UserPhotoMetadata>(id);

    public async Task<UserPhotoMetadata?> GetMetadataAsync(Guid id)
        => (await storage.FindAsync<UserPhotoMetadata>(id))?.Metadata;

    public Task<bool> DeleteAsync(Guid id)
        => storage.DeleteAsync<UserPhotoMetadata>(id);
}

// Через IObjectBucket<T> — типизированный бакет, инжектируется напрямую
public class PhotoService(IObjectBucket<UserPhotoMetadata> bucket)
{
    public Task UploadAsync(Guid id, Stream photo)
        => bucket.UploadAsync(id, new UserPhotoMetadata { FileName = "photo.jpg" }, photo);
}

API

IObjectStorageClient

Точка входа, аналог IMongoClient. Навигация к бакетам синхронная (без I/O).

IObjectBucket bucket              = client.GetBucket("my-bucket");
IObjectBucket<T> typed            = client.GetBucket<UserPhotoMetadata>();

IReadOnlyList<BucketInfo> buckets = await client.ListBucketsAsync();
await client.CreateBucketAsync("new-bucket", s => s.Versioning = BucketVersioning.Enabled);
await client.DropBucketAsync("old-bucket");

IObjectBucket

Управление бакетом, аналог IMongoDatabase.

bool exists = await bucket.ExistsAsync();
BucketSettings settings = await bucket.GetSettingsAsync();

await bucket.UpdateSettingsAsync(s =>
{
    s.Versioning = BucketVersioning.Enabled;
    s.Access     = BucketAccess.PublicRead;
    s.LifecycleRules.Add(new LifecycleRule("cleanup", ExpirationDays: 30, Prefix: "temp/"));
});

IObjectBucket<TMetadata>

Типизированные CRUD-операции, аналог IMongoCollection<T>. Наследует IObjectBucket.

Метод Описание
FindOneAsync(Guid, CancellationToken) Метаданные объекта. null если не найден.
OpenReadAsync(Guid, CancellationToken) Поток содержимого. null если не найден.
UploadAsync(Guid, TMetadata, Stream, CancellationToken) Загрузить объект.
DeleteOneAsync(Guid, CancellationToken) Удалить объект. false если не существовал.

IObjectStorage

Упрощённый фасад над IObjectStorageClient для обратной совместимости.

Метод Описание
FindAsync<T>(Guid, CancellationToken) Метаданные объекта. null если не найден.
ReadAsync<T>(Guid, CancellationToken) Поток содержимого. null если не найден.
UploadAsync<T>(Guid, T, Stream, CancellationToken) Загрузить объект.
DeleteAsync<T>(Guid, CancellationToken) Удалить объект. false если не существовал.

ObjectStorageOptions

Свойство Описание
ServiceUrl URL эндпоинта S3
AuthenticationRegion Регион авторизации
AccessKeyId Идентификатор ключа доступа
SecretAccessKey Секретный ключ доступа

BucketSettings

Свойство Тип Описание
Versioning BucketVersioning Disabled / Enabled / Suspended
Access BucketAccess Private / PublicRead
LifecycleRules List<LifecycleRule> Правила жизненного цикла

LifecycleRule(string Id, int? ExpirationDays, string? Prefix, bool Enabled)


Работа с JSON

Extension-методы ReadJsonAsync / UploadJsonAsync работают с любым IObjectMetadata — никаких дополнительных интерфейсов реализовывать не нужно.

public class ReportContent
{
    public string Title { get; set; }
    public decimal Value { get; set; }
}

public class ReportMetadata : IObjectMetadata   // обычный IObjectMetadata
{
    public string Author { get; set; }
    public DateTime CreatedAt { get; set; }
}
// Загрузка
await storage.UploadJsonAsync<ReportMetadata, ReportContent>(
    id, new ReportMetadata { Author = "admin" }, reportContent);

// Чтение — возвращает null если объект не найден
ReportContent? content = await storage.ReadJsonAsync<ReportMetadata, ReportContent>(id);

// Опционально: настройки сериализации
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
await storage.UploadJsonAsync<ReportMetadata, ReportContent>(id, metadata, content, options);
var result = await storage.ReadJsonAsync<ReportMetadata, ReportContent>(id, options);

// Через IObjectBucket<T>
await bucket.UploadJsonAsync<ReportMetadata, ReportContent>(id, metadata, content);
var result = await bucket.ReadJsonAsync<ReportMetadata, ReportContent>(id);

Исключения

При ошибках S3 бросается ObjectStorageException. Свойство StatusCode содержит HTTP-код ответа, InnerException — оригинальное AmazonS3Exception.

catch (ObjectStorageException ex) when (ex.StatusCode == HttpStatusCode.Forbidden) { }
catch (ObjectStorageException ex) { }

Тестирование

Пакет BrandUp.Extensions.ObjectStorage.Testing предоставляет in-memory реализацию всех интерфейсов без зависимостей от AWS SDK.

Настройка

services.AddFakeObjectStorage()
    .AddMapping<UserPhotoMetadata>("photos/users")
    .WithBucket("photos");       // предсоздать бакет (опционально)

Использование в тестах

// Стандартные интерфейсы работают как обычно
var storage = sp.GetRequiredService<IObjectStorage>();
var bucket  = sp.GetRequiredService<IObjectBucket<UserPhotoMetadata>>();
var client  = sp.GetRequiredService<IObjectStorageClient>();

// FakeObjectStore — инспекция и управление состоянием
var store = sp.GetRequiredService<FakeObjectStore>();

Assert.True(store.BucketExists("photos"));
Assert.Equal(1, store.GetObjectCount("photos"));

store.Clear();                              // сброс между тестами
store.CreateBucket("extra");               // ручное создание бакета
store.PutObject("photos", "key", bytes, metadata); // предзаполнение данными

Yandex Cloud Object Storage

Конфигурация

services.AddObjectStorage(opts =>
{
    opts.ServiceUrl           = "https://storage.yandexcloud.net";
    opts.AuthenticationRegion = "ru-central1";
    opts.AccessKeyId          = "<идентификатор статического ключа>";
    opts.SecretAccessKey      = "<секретный ключ>";
})
.AddMapping<UserPhotoMetadata>("my-bucket/photos");

Ключи доступа создаются в консоли Yandex Cloud: IAM → Сервисные аккаунты → Ключи доступа.

Совместимость

Функция YC
Загрузка / чтение / удаление объектов
Метаданные объектов
Создание / удаление бакетов
Список бакетов
Версионирование
Lifecycle rules
Управление доступом (ACL) ⚠️

ACL-операции работают через S3-совместимый API, однако публичный доступ может быть заблокирован политикой организации. Для управления публичным доступом рекомендуется консоль YC или CLI: yc storage bucket update --public-read.

Имена бакетов в Yandex Cloud уникальны глобально — не только в рамках вашего аккаунта.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.2.1 57 8/21/2026
2.1.4 101 8/16/2026
2.1.1 108 8/2/2026
2.0.4 105 8/1/2026
2.0.3 100 8/1/2026
1.0.6 122 6/24/2026
1.0.5 125 6/24/2026
1.0.4 116 6/12/2026
1.0.2 125 6/6/2026