ClsLib 1.0.10

dotnet add package ClsLib --version 1.0.10
                    
NuGet\Install-Package ClsLib -Version 1.0.10
                    
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="ClsLib" Version="1.0.10" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ClsLib" Version="1.0.10" />
                    
Directory.Packages.props
<PackageReference Include="ClsLib" />
                    
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 ClsLib --version 1.0.10
                    
#r "nuget: ClsLib, 1.0.10"
                    
#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 ClsLib@1.0.10
                    
#: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=ClsLib&version=1.0.10
                    
Install as a Cake Addin
#tool nuget:?package=ClsLib&version=1.0.10
                    
Install as a Cake Tool

ClsLib

Namespace: Cls · Target: .NET 10

Утилитарная библиотека: типизированные исключения, result-типы, структурированное логирование, вспомогательные функции.

Установка

dotnet add package ClsLib
using Cls;

Обзор классов

Класс Назначение
UExcept Типизированное исключение с enum-кодом. Поддерживает цепочки и дерево диагностики
UResponse / UResponse<T> Result-тип «успех или ошибка» без throw
GlobalErrors Общий enum кодов ошибок
Log Статический логгер (Debug output + event sink)
LogBox Scoped-логгер с breadcrumb-трассировкой
Functions Статические утилиты: timestamps, ID, MD5, string, directory
ExceptionExtensions Fluent-расширение для добавления данных в Exception.Data
UProcLog String-расширение для быстрого процедурного логирования

UExcept

Наследует System.Exception. Хранит Code — любой Enum.

new UExcept(GlobalErrors.NotFound, "Пользователь не найден");

// С вложенным исключением (формирует цепочку)
new UExcept(GlobalErrors.Exception, "Обёртка", innerException);

Ключевые методы

Метод Возврат Описание
GetUCode() int Составной код всей цепочки: code × 100^depth
GetExceptionTree() string Человекочитаемое дерево цепочки исключений
GetFullInfo() string Полная диагностика: сообщение, код, UCode, дерево
ToLog(LogBox proc) void Записывает GetFullInfo() в LogBox с уровнем Trace
var inner = new UExcept(GlobalErrors.NoData, "Пустой результат");
var ex    = new UExcept(GlobalErrors.NotFound, "Не найден", inner);

ex.GetUCode();        // 1_010_507  (10005*100 + 10007)
ex.GetExceptionTree();
// GlobalErrors.NotFound [10005]: Не найден
// ├─ Trace
// │  └─ at CategoryService.GetByIdAsync() ...
// └─ GlobalErrors.NoData [10007]: Пустой результат

GetExceptionTree() включает до 5 последних фреймов стека и содержимое exception.Data для каждого узла цепочки.


UResponse / UResponse<T>

UResponse (без данных)

Свойство Тип Описание
IsSuccess bool Флаг успеха
Error UExcept? Ошибка (null при успехе)
ExData Dictionary<string, object?> Произвольные доп. данные
var ok   = new UResponse(true);
var fail = new UResponse(new UExcept(GlobalErrors.NotFound, "Не найден"));

// Доп. данные (fluent)
var resp = new UResponse(true)
    .AddData(new Dictionary<string, object?> { ["userId"] = 42 });

UResponse<T> (с данными)

var ok   = new UResponse<int>(42);          // ok.IsSuccess=true, ok.Response=42
var fail = new UResponse<int>(
    new UExcept(GlobalErrors.NoData, "Нет данных")); // fail.IsSuccess=false

Типичный паттерн

public UResponse<User> GetUser(int id)
{
    var user = _db.Find(id);
    if (user is null)
        return new UResponse<User>(new UExcept(GlobalErrors.NotFound, $"User {id} not found"));
    return new UResponse<User>(user);
}

var result = GetUser(5);
if (result.IsSuccess)
    Console.WriteLine(result.Response!.Name);
else
    Console.WriteLine(result.Error!.Message);

GlobalErrors

Значение Код Описание
Exception 0 Неклассифицированное исключение
SecretStoreError 10001 Ошибка хранилища секретов
ArgumentNull 10002 Обязательный аргумент null
OperationCancelled 10003 Операция отменена
IncorrectArgument 10004 Недопустимое значение
NotFound 10005 Элемент не найден
AlreadyExists 10006 Элемент уже существует
NoData 10007 Нет данных

Собственные enum-ы — определяйте для конкретных доменов:

public enum EOrderService { PaymentFailed = 20_001, OutOfStock = 20_002 }
throw new UExcept(EOrderService.PaymentFailed, "Платёж отклонён");

Log (статический)

// Подключение приёмника
Log.NewMessage += (message, type) =>
    File.AppendAllText("app.log", $"[{type}] {message}\n");

// Запись
Log.Add("Сервис запущен");                         // тип: Message
Log.Add("Низкая память", ELogType.Warning);
Log.Add("Необработанная ошибка", ELogType.Error);

Формат: [15.02.2026 14:30:05.123] [Message] Сервис запущен

ELogType

Message · Warning · Error · Trace · Debug


LogBox

Scoped-логгер с «хлебными крошками». Накапливает путь трассировки.

Метод Возврат Описание
AddTrace(string) LogBox Добавляет сегмент пути. Мутирует this, возвращает this
CloneAs(string) LogBox Независимая копия с опциональным новым сегментом
Log(string, ELogType) void Логирует с полным путём
GetFullTrace() string Путь: A → B → C
var log = new LogBox("OrderService");
log.AddTrace("CreateOrder");
log.Log("Начало");
// [Message] OrderService → CreateOrder → Начало

// Клонирование для параллельных ветвей
var branchA = log.CloneAs("Validate");
var branchB = log.CloneAs("Persist");
branchA.Log("ОК"); // OrderService → CreateOrder → Validate → ОК
branchB.Log("ОК"); // OrderService → CreateOrder → Persist → ОК

Правило: используй CloneAs, никогда AddTrace для создания новой ветки. AddTrace мутирует оригинал — накопленные сегменты останутся во всех последующих вызовах.


Functions

// Временные метки
DateTime dt = Functions.TimeStampToDateTime(1739612400000);
long ts     = Functions.DateTimeToTimeStamp(DateTime.UtcNow);

// Генерация ID
string id = Functions.CreateId();                           // "aB3xKm-9pQwLz-Hy7nRt-Jk2VfX"
string s  = Functions.CreateId(countBlocks: 2, blockLength: 4); // "aB3x-9pQw"

// MD5
string hash = Functions.GetMd5Hash("hello world"); // "5eb63bbbe01eeed093cb22bb8f5acdc3"

// Логирование ошибок
catch (UExcept ex) { Functions.Error(ex, "Контекст", log); }
catch (Exception ex) { Functions.Error(ex, "Контекст", log); }

// Утилиты
Functions.GetMethodName();     // имя вызывающего метода
Functions.CopyDirectory(@"C:\src", @"C:\dst");

1234567.89.ToOut();                 // "1 234 567.89"
"hello".ToUpperOnlyFirstLetter();   // "Hello"

ExceptionExtensions

Fluent-расширение для добавления данных в Exception.Data. Отображается в GetExceptionTree().

throw new UExcept(GlobalErrors.NotFound, "Не найден")
    .AddData(new Dictionary<string, object?>
    {
        ["entityId"] = id,
        ["source"]   = "database"
    });

// GlobalErrors.NotFound [10005]: Не найден
// ├─ Trace
// │  └─ at ...
// └─ Data
//    ├─ entityId: 42
//    └─ source: database

UProcLog

String-расширение для быстрого одноразового логирования без LogBox.

"InitService".Log("Запуск");  // [Message] InitService Запуск
"InitService".Log("Готово");  // [Message] InitService Готово

Для структурированной трассировки используй LogBox.


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

Scoped LogBox на метод (главный паттерн)

public class CategoryService
{
    private static readonly LogBox Pref = new("CategoryService");

    public async Task<UResponse<CategoryDto>> GetByIdAsync(int id)
    {
        var _proc = Pref.CloneAs(Functions.GetMethodName());
        // путь: "CategoryService → GetByIdAsync"

        _proc.Log("Начало обработки");
        return await LoadFromDb(id, _proc);
    }

    private async Task<UResponse<CategoryDto>> LoadFromDb(int id, LogBox proc)
    {
        var _proc = proc.CloneAs(Functions.GetMethodName());
        // путь: "CategoryService → GetByIdAsync → LoadFromDb"
        _proc.Log($"Загрузка id={id}");
        // ...
    }
}

Ветвление по коду ошибки

var result = await GetCategoriesFromSlugPath(slugPath);
if (!result.IsSuccess)
{
    var error = result.Error!;

    if (error.Code is ESlugPath.EmptySegments)
        return Ok(GetRootCategories());

    throw new UExcept(EGetCategoryTree.FailGetCategories,
        $"Ошибка разбора пути: {slugPath}", error);
}

Catch-блок в контроллере (ASP.NET Core)

[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
    var _proc = Pref.CloneAs(Functions.GetMethodName());
    try
    {
        var result = await _service.GetUserAsync(id);

        if (!result.IsSuccess)
        {
            if (result.Error!.Code is EUserService.UserNotFound)
                return NotFound(ApiResponse<UserDto>.ErrorResult(result.Error));
            throw result.Error;
        }

        return Ok(ApiResponse<UserDto>.SuccessResult(result.Response!));
    }
    catch (UExcept ex)
    {
        Functions.Error(ex, ex.Message, _proc);
        if (ex.Code is HttpStatusCode code)
            return StatusCode((int)code, ApiResponse<UserDto>.ErrorResult(ex));
        return StatusCode(500, ApiResponse<UserDto>.ErrorResult(ex));
    }
    catch (Exception ex)
    {
        var uex = new UExcept(GlobalErrors.Exception, ex.Message, ex);
        Functions.Error(uex, "Ошибка GetUser", _proc);
        return StatusCode(500, ApiResponse<UserDto>.ErrorResult(uex));
    }
}

Два catch-блока — осознанный паттерн:

  • catch (UExcept) — типизированные ошибки бизнес-логики, возможен HTTP-маппинг
  • catch (Exception) — всё остальное оборачивается в UExcept для единого формата ответа
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.
  • net10.0

    • No dependencies.

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
1.0.10 150 3/16/2026