S3Lab.Box.Result 2.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package S3Lab.Box.Result --version 2.1.0
                    
NuGet\Install-Package S3Lab.Box.Result -Version 2.1.0
                    
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="S3Lab.Box.Result" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="S3Lab.Box.Result" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="S3Lab.Box.Result" />
                    
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 S3Lab.Box.Result --version 2.1.0
                    
#r "nuget: S3Lab.Box.Result, 2.1.0"
                    
#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 S3Lab.Box.Result@2.1.0
                    
#: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=S3Lab.Box.Result&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=S3Lab.Box.Result&version=2.1.0
                    
Install as a Cake Tool

S3Lab.Box

Решение для ASP.NET Core приложений, включающее библиотеки для аутентификации и работы с данными.

Проекты в решении

S3Lab.Box.Auth

Библиотека для аутентификации ASP.NET Core приложений с использованием API ключей.

Описание

S3Lab.Box.Auth предоставляет простое и эффективное решение для защиты API endpoints с помощью API ключей. Библиотека включает в себя middleware для проверки заголовка X-API-Key и расширения для удобной интеграции в ASP.NET Core приложения.

Возможности
  • 🔐 Аутентификация по API ключу через заголовок X-API-Key
  • 🚫 Автоматическое отклонение запросов без валидного ключа
  • 🔓 Исключения для определенных маршрутов (Scalar, OpenAPI)
  • ⚡ Поддержка preflight запросов (OPTIONS)
  • 🛠️ Простая интеграция через extension методы
Установка
dotnet add package S3Lab.Box.Auth
Быстрый старт
  1. Настройка конфигурации

Добавьте API ключ в ваш appsettings.json:

{
  "ApiKey": "your-secret-api-key-here"
}
  1. Регистрация сервисов

В Program.cs или Startup.cs:

using S3Lab.Box.Auth.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Добавление сервисов
builder.Services.AddApplicationReferences(builder.Configuration);

var app = builder.Build();

// Регистрация middleware
app.UseApiKeyMiddleware();

app.Run();
  1. Использование

После настройки все запросы к вашему API должны включать заголовок X-API-Key с валидным ключом:

curl -H "X-API-Key: your-secret-api-key-here" https://your-api.com/endpoint
Исключения

Middleware автоматически пропускает следующие типы запросов:

  • OPTIONS запросы (preflight для CORS)
  • Scalar endpoints (/scalar/*)
  • OpenAPI endpoints (/openApi/*)
Конфигурация

API ключ должен быть указан в конфигурации приложения:

{
  "ApiKey": "your-secret-api-key-here"
}

Для production окружения рекомендуется использовать переменные окружения:

export ApiKey="your-production-api-key"
Обработка ошибок

При отсутствии или неверном API ключе middleware возвращает:

  • HTTP Status Code: 401 Unauthorized
  • Response Body: "Unauthorized: Invalid or missing X-API-Key"
Безопасность
  • API ключ должен быть достаточно длинным и случайным
  • Используйте HTTPS в production окружении
  • Не храните API ключи в исходном коде
  • Регулярно ротируйте API ключи

S3Lab.Box.Data

Библиотека для работы с данными в ASP.NET Core приложениях, предоставляющая базовые сущности, интерфейсы и репозиторий для Entity Framework Core.

Описание

S3Lab.Box.Data предоставляет набор базовых классов и интерфейсов для упрощения работы с данными в .NET приложениях. Библиотека включает в себя готовые сущности с аудитом и архивированием, универсальный репозиторий и расширения для Entity Framework Core.

Возможности
  • 🏗️ Базовые сущности с поддержкой различных типов ключей
  • 📝 Аудит сущностей (создание, изменение, пользователи)
  • 🗄️ Архивирование сущностей (мягкое удаление)
  • 📚 Универсальный репозиторий с полным набором CRUD операций
  • 🔍 Поддержка Include для связанных сущностей
  • ⚡ Асинхронные операции с поддержкой CancellationToken
  • 🛠️ Расширения для Entity Framework Core
Установка
dotnet add package S3Lab.Box.Data
Требования
  • .NET 9.0 или выше
  • Entity Framework Core

Структура библиотеки

Сущности (Entities)

Entity<TKey>

Базовая сущность с идентификатором:

public abstract class Entity<TKey> : IEntity<TKey>, IEntity
{
    public required TKey Id { get; set; }
}
AuditableEntity<TKey, TUserKey>

Сущность с аудитом (отслеживание создания и изменения):

public abstract class AuditableEntity<TKey, TUserKey> : Entity<TKey>, IAuditableEntity<TUserKey>
{
    public TUserKey CreatedBy { get; set; }
    public TUserKey UpdatedBy { get; set; }
    public DateTime Created { get; set; }
    public DateTime? Updated { get; set; }
}
ArchivableEntity<TKey, TUserKey>

Архивируемая сущность с мягким удалением:

public class ArchivableEntity<TKey, TUserKey> : AuditableEntity<TKey, TUserKey>, IArchivableEntity
{
    public bool IsDeleted { get; set; }
}
DictionaryEntity<TKey>

Справочная сущность с именем:

public abstract class DictionaryEntity<TKey> : IDictionaryEntity<TKey>
{
    public TKey Id { get; set; }
    public required string Name { get; set; }
}

Интерфейсы (Interfaces)

IEntity<TKey>

Базовый интерфейс для сущностей с идентификатором:

public interface IEntity<TKey>
{
    TKey Id { get; set; }
}
IAuditableEntity<TUserKey>

Интерфейс для аудируемых сущностей:

public interface IAuditableEntity<TUserKey>
{
    TUserKey CreatedBy { get; set; }
    TUserKey UpdatedBy { get; set; }
    DateTime Created { get; set; }
    DateTime? Updated { get; set; }
}
IArchivableEntity

Интерфейс для архивируемых сущностей:

public interface IArchivableEntity
{
    bool IsDeleted { get; set; }
}
IRepository<TEntity, TKey>

Универсальный интерфейс репозитория с полным набором CRUD операций:

public interface IRepository<TEntity, TKey>
{
    // Получение по ID
    Task<TEntity?> GetByIdAsync(TKey id);
    Task<TEntity?> GetByIdAsync(TKey id, IEnumerable<string> includePaths);
    Task<TEntity?> GetByIdAsync(TKey id, bool asNoTracking);
    
    // Получение списка по ID
    Task<List<TEntity>> GetByIdListAsync(IEnumerable<TKey> idList);
    
    // Добавление
    Task<TEntity> AddAsync(TEntity entity);
    Task AddRangeAsync(IEnumerable<TEntity> entities);
    
    // Обновление
    Task UpdateAsync(TEntity entity);
    
    // Удаление
    Task DeleteAsync(TEntity entity);
    Task DeleteRangeAsync(IEnumerable<TEntity> entities);
    
    // Сохранение
    Task SaveAsync();
    
    // Проверка существования
    Task<bool> IsExistAsync(TKey id);
}

Репозиторий (Repository)

Repository<TEntity, TKey>

Универсальная реализация репозитория с поддержкой:

  • Асинхронных операций
  • CancellationToken
  • Include для связанных сущностей
  • AsNoTracking для оптимизации производительности
  • Пакетных операций
UnitOfWork

Реализация паттерна Unit of Work для управления транзакциями:

public interface IUnitOfWork : IDisposable
{
    IRepository<TEntity, TKey> Repository<TEntity, TKey>();
    Task<int> SaveChangesAsync();
    Task<IDbContextTransaction> BeginTransactionAsync();
    Task<T> ExecuteInTransactionAsync<T>(Func<Task<T>> operation);
}

Возможности UnitOfWork:

  • 🏗️ Централизованное управление репозиториями
  • 💾 Автоматическое управление транзакциями
  • 🔄 Поддержка отката изменений при ошибках
  • ⚡ Кэширование репозиториев для оптимизации
  • 🛡️ Безопасное освобождение ресурсов

Расширения (Extensions)

QueryableExtensions

Расширения для работы с IQueryable:

public static IQueryable<TEntity> AddIncludes<TEntity, TKey>(
    this IQueryable<TEntity> entities, 
    IEnumerable<string>? includePaths)
ServiceCollectionExtensions

Расширения для регистрации сервисов в DI:

// Регистрация UnitOfWork
services.AddS3LabBoxData();

// Регистрация конкретного репозитория
services.AddRepository<User, int, UserRepository>();

// Регистрация базового репозитория
services.AddRepository<Product, int>();

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

1. Создание сущности

public class User : AuditableEntity<int, int>
{
    public string Name { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

public class Category : DictionaryEntity<int>
{
    public Category(int id, string name) : base(id, name)
    {
    }
}

2. Создание репозитория

public class UserRepository : Repository<User, int>
{
    public UserRepository(DbContext context) : base(context)
    {
    }
    
    // Дополнительные методы специфичные для User
    public async Task<User?> GetByEmailAsync(string email)
    {
        return await DbSet.FirstOrDefaultAsync(u => u.Email == email);
    }
}

3. Регистрация в DI

// Program.cs
builder.Services.AddScoped<UserRepository>();
builder.Services.AddScoped<IRepository<User, int>, UserRepository>();

4. Использование

public class UserService
{
    private readonly IRepository<User, int> _userRepository;
    
    public UserService(IRepository<User, int> userRepository)
    {
        _userRepository = userRepository;
    }
    
    public async Task<User> CreateUserAsync(User user)
    {
        user.Created = DateTime.UtcNow;
        user.CreatedBy = 1; // ID текущего пользователя
        
        return await _userRepository.AddAsync(user);
    }
    
    public async Task<User?> GetUserWithDetailsAsync(int id)
    {
        return await _userRepository.GetByIdAsync(id, new[] { "Orders", "Profile" });
    }
    
    public async Task<List<User>> GetUsersByIdsAsync(IEnumerable<int> ids)
    {
        return await _userRepository.GetByIdListAsync(ids);
    }
}

5. Использование UnitOfWork

public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;
    
    public OrderService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    
    public async Task<Order> CreateOrderWithItemsAsync(Order order, List<OrderItem> items)
    {
        // Использование транзакции для атомарной операции
        return await _unitOfWork.ExecuteInTransactionAsync(async () =>
        {
            var orderRepo = _unitOfWork.Repository<Order, int>();
            var itemRepo = _unitOfWork.Repository<OrderItem, int>();
            
            // Создаем заказ
            var createdOrder = await orderRepo.AddAsync(order);
            
            // Добавляем товары к заказу
            foreach (var item in items)
            {
                item.OrderId = createdOrder.Id;
                await itemRepo.AddAsync(item);
            }
            
            // Сохраняем все изменения
            await _unitOfWork.SaveChangesAsync();
            
            return createdOrder;
        });
    }
    
    public async Task<bool> TransferBetweenOrdersAsync(int fromOrderId, int toOrderId, int itemId)
    {
        try
        {
            using var transaction = await _unitOfWork.BeginTransactionAsync();
            
            var itemRepo = _unitOfWork.Repository<OrderItem, int>();
            
            // Получаем товар
            var item = await itemRepo.GetByIdAsync(itemId);
            if (item == null) return false;
            
            // Обновляем заказ
            item.OrderId = toOrderId;
            await itemRepo.UpdateAsync(item);
            
            // Сохраняем изменения
            await _unitOfWork.SaveChangesAsync();
            
            // Подтверждаем транзакцию
            await transaction.CommitAsync();
            
            return true;
        }
        catch
        {
            // Транзакция автоматически откатится при исключении
            return false;
        }
    }
}

Примеры использования

Работа с аудируемыми сущностями

public class Product : AuditableEntity<int, int>
{
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
}

// Создание
var product = new Product
{
    Name = "Sample Product",
    Price = 99.99m,
    Created = DateTime.UtcNow,
    CreatedBy = currentUserId
};

await _repository.AddAsync(product);

// Обновление
product.Price = 89.99m;
product.Updated = DateTime.UtcNow;
product.UpdatedBy = currentUserId;

await _repository.UpdateAsync(product);

Работа с архивируемыми сущностями

public class Order : ArchivableEntity<int, int>
{
    public string OrderNumber { get; set; } = string.Empty;
    public decimal Total { get; set; }
}

// Мягкое удаление
var order = await _repository.GetByIdAsync(orderId);
if (order != null)
{
    order.IsDeleted = true;
    order.Updated = DateTime.UtcNow;
    order.UpdatedBy = currentUserId;
    
    await _repository.UpdateAsync(order);
}

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

// Получение пользователя с заказами и профилем
var user = await _userRepository.GetByIdAsync(
    userId, 
    new[] { "Orders", "Profile", "Orders.Items" }
);

// Получение без отслеживания изменений
var user = await _userRepository.GetByIdAsync(
    userId, 
    new[] { "Orders" }, 
    asNoTracking: true
);

Пакетные операции

// Добавление нескольких сущностей
var users = new List<User>
{
    new User { Name = "User1", Email = "user1@example.com" },
    new User { Name = "User2", Email = "user2@example.com" }
};

await _userRepository.AddRangeAsync(users);
await _userRepository.SaveAsync();

// Удаление нескольких сущностей
var usersToDelete = await _userRepository.GetByIdListAsync(userIds);
await _userRepository.DeleteRangeAsync(usersToDelete);
await _userRepository.SaveAsync();

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

DbContext

public class ApplicationDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Category> Categories { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        
        // Конфигурация для аудируемых сущностей
        modelBuilder.Entity<User>()
            .Property(u => u.Created)
            .HasDefaultValueSql("GETUTCDATE()");
            
        // Конфигурация для архивируемых сущностей
        modelBuilder.Entity<Order>()
            .HasQueryFilter(o => !o.IsDeleted);
    }
}

Производительность

Рекомендации

  1. Используйте AsNoTracking для операций только чтения:

    var users = await _repository.GetByIdAsync(id, asNoTracking: true);
    
  2. Применяйте Include только когда необходимо:

    // Только при необходимости связанных данных
    var user = await _repository.GetByIdAsync(id, new[] { "Orders" });
    
  3. Используйте пакетные операции для множественных изменений:

    await _repository.AddRangeAsync(entities);
    await _repository.SaveAsync(); // Одно сохранение для всех
    
  4. Применяйте CancellationToken для длительных операций:

    var users = await _repository.GetByIdListAsync(ids, cancellationToken);
    

Лицензия

MIT License

Автор

Sazonov Andrei

Версия

1.0.0

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

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on S3Lab.Box.Result:

Package Downloads
S3Lab.Box.Data

Библиотека для работы с данными в ASP.NET Core приложениях, предоставляющая базовые сущности, интерфейсы и репозиторий для Entity Framework Core.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.2.0 229 6/27/2025
2.1.0 140 6/27/2025
2.0.0 207 6/26/2025
1.0.0 185 2/12/2025