ClsLib 1.0.10
dotnet add package ClsLib --version 1.0.10
NuGet\Install-Package ClsLib -Version 1.0.10
<PackageReference Include="ClsLib" Version="1.0.10" />
<PackageVersion Include="ClsLib" Version="1.0.10" />
<PackageReference Include="ClsLib" />
paket add ClsLib --version 1.0.10
#r "nuget: ClsLib, 1.0.10"
#:package ClsLib@1.0.10
#addin nuget:?package=ClsLib&version=1.0.10
#tool nuget:?package=ClsLib&version=1.0.10
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 | Versions 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. |
-
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 |