csharpproglib | Unsorted

Telegram-канал csharpproglib - Библиотека шарписта | C#, F#, .NET, ASP.NET

23284

Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

Subscribe to a channel

Библиотека шарписта | C#, F#, .NET, ASP.NET

Интерполяция строк не бесплатна

Строки в горячих участках вашего кода бьют по памяти сильнее чем кажется. В ASP.NET они часто оказываются в топе аллокаторов в профайлере.

Что создаёт лишние строки

• Интерполяция

var key = $"{userId}:{tenantId. Каждый вызов порождает новый string и новый массив char.

• string.Format

string.Format("{0}-{1}", a, b); работает по той же схеме создаёт новый объект и буфер под символы.

• Частые ToString()

request.Headers["X-Id"].ToString(); при каждом запросе снова строит строку из заголовка.

Как сделать безопаснее

• Использовать структурированное логирование

logger.LogInformation("User {UserId} logged in", userId);

В этом случае ILogger не формирует строку когда соответствующий уровень логов отключён, а значения попадают в структурированные поля записи.

• Не вызывать ToString() без необходимости

Формируйте строку только там где она действительно нужна в ответе или в редком логировании, а не в общем горячем пути.

• В особо чувствительных местах использовать Span и ValueStringBuilder

Они позволяют собирать текст в переиспользуемом буфере и заметно снизить количество мусора.

Если код выполняется на каждом запросе, строковая интерполяция и лишние преобразования в string перестают быть дешёвым сахаром и становятся реальным источником аллокаций.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

WANTED: .NET-РЕЦЕДИВИСТ

Разыскивается эксперт, способный приручить C# и заставить его работать идеально. Мы знаем, что у тебя есть секретные приёмы, которыми пора поделиться с комьюнити.

Приметы:

— глубоко знает экосистему .NET и может сравнить её с Java или Go;
— умеет проектировать сложные системы без «костылей»;
— готов выступать на большую аудиторию в качестве автора или ментора;
— хочет монетизировать свой профессиональный опыт.

Что в контракте:

— гонорар за интеллектуальный вклад;
— статус официального эксперта Proglib Academy;
— заметный буст личного бренда.

Признаться во всём здесь

P.S. Знаешь сильного «шарписта»? Сдай его следствию — перешли пост.

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

😊 Потоковый ответ вместо буферизации

Во многих API до сих пор пишут методы вида public IEnumerable<OrderDto> GetOrders() и думают что это ленивый возврат данных. На деле фреймворк вынужден сначала полностью пройти по IEnumerable, собрать коллекцию, а уже потом целиком сериализовать ее в JSON и отправить в сеть.

Большой список целиком оказывается в куче, всплеск аллокаций ускоряет сборку мусора, а клиент ждет первый байт до тех пор пока не будет готов весь массив данных.

В современных версиях .NET намного безопаснее отдавать последовательность как IAsyncEnumerable<T>. В этом случае ASP.NET может сериализовать элементы по мере их появления и выводить их в ответ потоком вместо полной буферизации результата.

Альтернативный вариант — явно использовать Results.Stream и JsonSerializer.SerializeAsync(stream, data) чтобы отдать JSON как поток байтов и держать в памяти лишь небольшой кусок данных.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🥹🥹 Можно заказать на амазоне

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#garbage_collector

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

⚙️ Поиск дубликатов с LINQ

Когда коллекция растет, руками гонять двойные циклы для поиска дубликатов уже не хочется. В .NET это хорошо решается комбинацией LINQ и HashSet, плюс классическими GroupBy и Distinct.

LINQ Any и HashSet

Идея простая: HashSet хранит только уникальные элементы. Метод Add возвращает false если такое значение уже было. Значит можно пробежать коллекцию через Any и остановиться на первом дубликате:

public static bool HasDuplicatesAny<T>(IEnumerable<T> source)
{
HashSet<T> seen = new();

return source.Any(item => !seen.Add(item));
}


Метод возвращает true как только встретится элемент который не удалось добавить в набор.

LINQ GroupBy и Count 1

Если нужны сами дубликаты, а не только факт их наличия, помогает GroupBy. Мы группируем по значению и фильтруем группы в которых больше одного элемента:
public static IEnumerable<T> GetDuplicatesGroupBy<T>(IEnumerable<T> source)
{
return source
.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
}


LINQ Distinct и подсчет элементов

Иногда достаточно проверить есть ли дубликаты, не вытаскивая их. Тогда можно сравнить размер исходной коллекции и количества уникальных элементов после Distinct:
public static bool HasDuplicatesDistinct<T>(IEnumerable<T> source)
{
int total = source.Count();
int unique = source.Distinct().Count();

return unique != total;
}


Для быстрых проверок чаще всего хватает Any + HashSet. GroupBy удобно когда нужны сами дубликаты.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

AI-агенты в продакшн: промышленный стандарт архитектуры

В Enterprise-разработке на первый план выходит контроль и предсказуемость. Мы учим проектировать ИИ-агентов как надёжные системы со строгой логикой и мониторингом.

Ключевые модули:


управление состоянием в LangGraph для проектирования сложных стейт-машин;
архитектура `RAG` на базе Pinecone или Chroma для обоснованной генерации ответов;
промышленная автоматизация через n8n для интеграции логики в бизнес-процессы;
безопасность и observability с внедрением LangSmith и Guardrails для аудита системы.

Результат — масштабируемая система, готовая к интеграции в ваш стек.

Подробности курса

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🤨 Lazy<T> против всех синглтонов

Lazy<T> в C# стал де-факто стандартом для thread-safe ленивой инициализации. Забудьте lock, volatile и двойные проверки.

Проблемы классического синглтона:

public sealed class ClassicSingleton
{
private static ClassicSingleton _instance;
private static readonly object _lock = new object();

private ClassicSingleton()
{
// 2 секунды на реальную БД/файлы
Thread.Sleep(2000);
Console.WriteLine("ClassicSingleton создан");
}

public static ClassicSingleton Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
_instance ??= new ClassicSingleton();
}
}
return _instance;
}
}
}


Lazy<T> решает всё элегантно:
public sealed class LazySingleton
{
private static readonly Lazy<LazySingleton> _lazy = new Lazy<LazySingleton>(() =>
{
Console.WriteLine("LazySingleton создан (ТОЛЬКО РАЗ)");
Thread.Sleep(2000); // Имитация тяжёлой работы
return new LazySingleton();
});

private LazySingleton() { }

public static LazySingleton Instance => _lazy.Value;
public static bool IsInitialized => _lazy.IsValueCreated;
}


Реальный многопоточный тест:
static async Task TestPerformance()
{
var stopwatch = Stopwatch.StartNew();

var tasks = Enumerable.Range(0, 1000)
.Select(i => Task.Run(() =>
{
var instance = LazySingleton.Instance;
return instance.GetHashCode();
}))
.ToArray();

var results = await Task.WhenAll(tasks);

stopwatch.Stop();
Console.WriteLine($"1000 потоков: {stopwatch.ElapsedMilliseconds}ms");
Console.WriteLine($"Уникальных объектов: {results.Distinct().Count()}");
Console.WriteLine($"Инициализировано: {LazySingleton.IsInitialized}");
}


Lazy<T> — это не хак, а официальный стандарт Microsoft.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💃 Пред-предновогодний дайджест

Вспомним что происходило на этой неделе.

GetElapsedTime сам посчитает время выполнения

Пишем письмо Деду Морозу

Пагинация и фильтрация через красоту

Сотрудника Amazon уволили из-за пинга

Почитать:

Подборка ИИ-инструментов для поиска работы за рубежом

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💃 Волшебство для больших проектов

Partial классы — это C#-хакинг, который разбивает один класс на несколько файлов, не ломая компиляцию. Идеально для автогенерации, командной работы и масштабирования монстров-кода.

Представьте: WinForms или WPF дизайнер генерирует кучу кода в .Designer.cs, а вы хотите добавить свою логику. Без partial пришлось бы вручную мержить изменения или наследоваться с кучей override. Partial решает это элегантно — основной класс в вашем файле, автокод в отдельном.

Все части класса должны иметь одинаковые модификаторы доступа и использовать ключевое слово partial. Компилятор проверит согласованность.

Живой пример:

// Employee.Core.cs — базовая структура
public partial class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }

public partial void ValidateName();
public partial void ValidateSalary();

public void Hire()
{
ValidateName();
ValidateSalary();
Console.WriteLine($"{Name} нанят с зарплатой {Salary:C}!");
}
}

// Employee.Validation.cs — бизнес-правила
public partial class Employee
{
public partial void ValidateName()
{
if (string.IsNullOrWhiteSpace(Name) || Name.Length < 2)
throw new ArgumentException("Имя должно быть не короче 2 символов!");
}

public partial void ValidateSalary()
{
if (Salary < 50000) throw new ArgumentException("Зарплата не может быть ниже 50k!");
}
}

// Employee.Extensions.cs — расширения (опционально)
public partial class Employee
{
public void Promote() => Salary *= 1.2m;
}


Partial методы уникальны: если реализация отсутствует, метод полностью удаляется из IL. Идеально для опциональных хуков в генерируемом коде.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🎓 Твой опыт стоит дорого — стань экспертом Proglib Academy

Чувствуешь, что накопил достаточно знаний, чтобы делиться ими с другими?

Мы ищем сильных практиков, которые хотят попробовать себя в роли:

— преподавателей;
— авторов курсов;
— наставников.

Это возможность не только монетизировать экспертизу, но и прокачать личный бренд, структурировать собственные знания и вырастить новое поколение специалистов.

👉 Заполни короткую анкету

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#garbage_collector

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💻 Свежий контент для Copilot

Проблема с Copilot: он не знает о новых штуках вроде Agent Framework. Решение от Microsoft: MCP сервер дает доступ к свежей .NET-документации прямо в инструментах разработки.

Сервер передает Copilot актуальные данные: гайды, код, уроки. Идеально для .NET 10, Aspire или оптимизации старых приложений. Контекст адаптируется под код.

➡️ Как всё это настроить

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💲 Дорогое логирование только в dev

Иногда нужно навесить на код тяжёлую отладочную диагностику, но в проде за неё платить не хочется. Для таких случаев есть атрибут Conditional, который полностью выкидывает вызовы метода из Release сборки.

Базовый пример:

[Conditional("DEBUG")]
public static void Trace(string message)
{
Console.WriteLine("[TRACE] " + message);
}


Это удобно для временного трассинга, сложных проверок и дорогих assert’ов, которые нужны только при разработке. Debug.Assert и Debug.WriteLine работают так же — они помечены [Conditional("DEBUG")], поэтому автоматически исчезают из релизной сборки.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

IDE-навигация для C# прямо в браузере

Привычка к мощным инструментам вроде Visual Studio или Rider делает работу с «голым» текстом в веб-интерфейсе GitLab мучительной. Особенно когда в пулл-реквесте нужно провалиться в определение класса или найти все использования метода, чтобы убедиться, что рефакторинг ничего не сломал.

На платформе SourceCraft для C# проектов реализована полноценная навигация по коду. Система строит семантический индекс, позволяя использовать Go to Definition и Find Usages непосредственно в окне просмотра пулл-реквеста. Это избавляет от необходимости стягивать ветку локально при проверке.

Посмотрите, как это работает на практике → https://sourcecraft.dev/code-navigation-demo/uikit/pr/2040

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🛠 Инструмент для трассировки без шума в коде

В ASP.NET трассировка маршрутизации, middleware и хостинга держится не на конкретном логгере, а на связке DiagnosticSource и DiagnosticListener.

Смысл DiagnosticListener в том что вы можете из кода публиковать диагностические события, не навязывая никому ни конкретный логгер, ни конкретный APM.

Источник событий ничего не знает о подписчиках, а подписчики могут подключаться и отключаться динамически, не требуя изменений основной логики.

Простой пример:

public static class OrderDiagnostics
{
public static readonly DiagnosticListener Listener =
new("MyApp.Orders");
}

public async Task ProcessOrder(Order order)
{
if (OrderDiagnostics.Listener.IsEnabled("OrderProcessed"))
OrderDiagnostics.Listener.Write("OrderProcessed", new { order.Id });

// основная логика обработки
}


Если никто не подписан, проверка IsEnabled сразу вернет false и код почти ничего не стоит по времени. Как только появляется listener, он может наблюдать за событиями, строить трейс, метрики или слать данные в OpenTelemetry.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🛠 ToonEncoder для .NET

ToonEncoder — это библиотека, которая кодирует данные в TOON. TOON описывается как компактное человекочитаемое представление той же модели данных что и JSON, но с упором на экономию токенов в промптах для LLM.

Практический кейс для айтишников это подготовка данных для LLM, например список логов, результатов поиска, объектов из базы, или пачка тул коллов, где табличный вид дает меньше лишней пунктуации и меньше повторяющихся ключей.

Пример:

using Cysharp.AI;

var users = new User[]
{
new (1, "Alice", "admin"),
new (2, "Bob", "user"),
};

string toon = ToonEncoder.Encode(users);
Console.WriteLine(toon);

string toon2 = ToonEncoder.EncodeAsTabularArray(users);
Console.WriteLine(toon2);

Console.WriteLine(toon == toon2); // same result

public record User(int Id, string Name, string Role);


У TOON есть режимы с разными разделителями, включая таб и пайп, чтобы еще чуть подкрутить токенизацию под конкретный ввод.

➡️ Репозиторий

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

⚙️ Yield в упрощает итерацию

Yield позволяет создавать итераторы, возвращая элементы коллекции по одному, без загрузки всего в память сразу.

Как работает yield return

При yield return код возвращает значение и сохраняет состояние для следующей итерации в foreach или LINQ. Компилятор генерирует класс, реализующий IEnumerable<T>, с MoveNext() для продолжения.

Пример простого генератора четных чисел:

IEnumerable<int> EvenNumbers(int max) {
for (int i = 0; i <= max; i += 2) {
yield return i;
}
}


foreach по нему выдаст 0, 2, 4... лениво, только при запросе.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🎅 Секретный Санта для айтишников от Proglib.academy

Весь этот год команда Академии запускала курсы для айтишников. А под Новый год мы запускаем новый курс по ИИ-агентам и ставим под ёлку самый свежий стек 2025 года и обучение проектированию автономных нейросетевых экосистем — от LLM и ReAct-циклов до мультиагентных систем, LangGraph, AutoGen и продакшн-практик.

🎁 Хотим дарить подарки и приглашаем вас поучаствовать в конкурсе:

1️⃣ Упомяните курс Академии у себя в блоге.
2️⃣ Пришлите скрин сюда.
3️⃣ Получите секретный промокод на 10 000 ₽ при оплате любого курса.

Подходит всё — соцсети, блоги, Telegram-каналы от 300 подписчиков и более.

🎄 Акция действует до Нового года.

Win-win, всё как мы любим!

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🎚 Подборка вакансий для шарпистов

Backend-разработчик C# на удалёнку.

.NET Developer (Middle) — удалёнка или офис в СПб.

Senior Backend-разработчик от 365 000 ₽

➡️ Еще больше топовых вакансий — в нашем канале C# Jobs

🐸 Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🛠 RoomSharp 0.4.3: миграции для продакшена

RoomSharp смешивает декларативные [AutoMigration] и императивные классы миграций. Автоматически обрабатывает переименования таблиц, колонок, добавление/удаление полей. MigrationManager следит за версиями в __room_metadata, предупреждает о деструктивных изменениях и запускает колбэки.

Установка — dotnet add package RoomSharp плюс провайдеры вроде RoomSharp.SqlServer. Расширения RoomSharp.Extensions для конфига.

📎 В блоге разработчиков много полезной информации

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🗂 Работа и пет-проекты с одного ПК

Работаете днём в корпоративном репо, вечером в личном на GitHub. Один ПК, но email и ключи подписи разные. Ручная смена настроек Git каждый раз бесит и приводит к косякам с коммитами.

Условные includeIf решают всё

Добавьте в ~/.gitconfig пару строк. Git сам подхватит нужный конфиг по пути к папке или remote URL.

Для рабочих папок загрузит корпоративный email:

[includeIf "gitdir:~/work/"] path = .gitconfig-corp


Личные репозитории получат ваш домашний email автоматически:
[includeIf "hasconfig:remote.*.url:https://github.com/вашеимя/**"] path = .gitconfig-personal


Забудьте про git config --global user.email каждый раз.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🧠 When и Unless для умных проверок

В FluentValidation условная валидация запускает правила только при нужных условиях. When и Unless экономят циклы и делают валидаторы читаемыми.

When = «проверить, если условие верно»
Unless = «проверить, если условие НЕ верно»

Пример:

RuleFor(x => x.ShippingAddress)
.NotEmpty()
.When(x => x.DeliveryMethod == "Express");

RuleFor(x => x.CreditCard)
.NotEmpty()
.Unless(x => x.PaymentMethod == "PayPal");


When проверяет условие перед правилом. Express доставка требует адрес, PayPal не требует карту. Логика в одном месте без if-else в контроллере.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

AI-агенты в Enterprise: взгляд .NET разработчика

Пока стартапы играются с Python-скриптами, энтерпрайз требует архитектуры. Мультиагентные системы в 2026 году — это, по сути, новые микросервисы.

В обновленном курсе по AI-агентам мы сместили фокус с простого «кодинга» на системное проектирование и архитектуру.

Что важного для архитектора:

Оркестрация: Разбор LangGraph (графы состояний) и AutoGen.
RAG & Vector DBs: Интеграция с Pinecone/Weaviate (актуально для корпоративных баз знаний).
Инфраструктура: Deployment, GPU-кластеры и AgentOps (мониторинг).

Курс разделен на треки. Если не хотите писать на Python, выбирайте Overview — поймете принципы построения систем, протоколы MCP и A2A коммуникацию.

⚡️ Offer 3-in-1:

Покупаете курс по агентам — забираете два любых других бесплатно. Отличный шанс взять «Алгоритмы» или «Паттерны».

Изучить программу

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🧑‍🎓 Диплом = 15% к зарплате

Диплом в IT вещь нестабильная. Одним подавай три профильных, чтобы устроиться, другие косо взглянут на любой диплом, который не из МФТИ.

В карточках собрали факты про эту корочку. Листайте и проверяйте сколько вам можно накинуть за диплом.

➡️ Полный материал

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

✏️ Вопрос с собеса

Админ принёс актуальный вопрос, который ему задали вчера на собеседовании.

Чем отличаются IQueryable<T> и IEnumerable<T> помимо синтаксиса?

Можете оставить свой ответ в комментариях и сравнить его с нашим.

👉 Посмотреть ответ в нашем канале с задачами

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#dotnet_challenge

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

😁 Он вам не веб-сервис

Вы замечали, что Windows работает не так, как раньше? Это всё из-за новомодных ИИ и веб-элементов. Первое пишет, а второе лагает.

Наткнулись на видео, где всё это выпиливают из актуальной Windows 11. Результат вас не порадует, но зато вы узнаете на что конкретно жаловаться в Microsoft.

➡️ Смотреть видео

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🔍 Подборка ИИ-инструментов для поиска работы за рубежом

На сайте Библиотеки программиста вышла обновлённая подборка AI сервисов для тех, кто хочет искать работу в IT за пределами своей страны.

Вместо того чтобы пытаться вручную тянуть LinkedIn, job‑борды и подготовку к интервью, имеет смысл собрать для себя связку из нескольких AI сервисов и переложить на них максимум рутины.

➡️ Список сервисов

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

⚙️Паттерн пагинации и фильтрации через один запрос и нормальные DTO

Пагинация в API часто превращается либо в магию репозиториев, либо в жуткий копипаст. Лучше держать всё предельно простым: один запрос с фильтрами, подсчётом и проекцией в DTO.

Что вообще хотим от пагинации

Когда фронт просит список пользователей, ему нужно не только «20 штук с offset», а нормальные данные

• Текущая страница.
• Размер страницы.
• Список элементов.
• Общее количество записей под этими фильтрами.

Контейнер для любого списка: пользователей, заказов или логов.

public sealed record Paginated<T>(
IReadOnlyList<T> Items,
int Page,
int Size,
int Total
);

• Items то, что реально отображаем.
• Page номер текущей страницы.
• Size сколько элементов на странице.
• Total сколько записей всего под заданным фильтром.

Зачем DTO, а не сущность из EF

• EF сущность часто содержит поля, которые нельзя светить наружу (пароли, внутренние флаги, технические поля).

• DTO можно менять отдельно от внутренней модели база может жить своей жизнью, а API остаётся стабильным.

• EF Core умеет проецировать прямо в DTO через Select, не тянуть все поля сущности и не включать трекинг.

В итоге хендлер не выкидывает наружу сырые сущности, а отдаёт ровно то, что нужно клиенту.

Как выглядит запрос сверху
public sealed record SearchUsersQuery(
string? Q,
int Page = 1,
int Size = 20
) : IRequest<Paginated<UserSummary>>;

• Q — строка поиска.
• Page — номер страницы.
• Size — размер страницы.

Контроллер ничего не знает о базе и EF он просто пробрасывает запрос в Application слой:
[HttpGet]
public async Task<ActionResult<Paginated<UserSummary>>> Search(
[FromQuery] string? q,
[FromQuery] int page,
[FromQuery] int size,
ISender sender,
CancellationToken ct
)
{
var result = await sender.Send(new SearchUsersQuery(q, page, size), ct);
return Ok(result);
}


Что делает хендлер под капотом
public async Task<Paginated<UserSummary>> Handle(
SearchUsersQuery query,
CancellationToken ct)
{
var users = _db.Users.AsQueryable();

if (!string.IsNullOrWhiteSpace(query.Q))
{
var q = query.Q.Trim();
users = users.Where(u =>
u.Email.Contains(q) ||
u.Name.Contains(q));
}

var total = await users.CountAsync(ct);

var items = await users
.OrderBy(u => u.Email)
.Skip((query.Page - 1) * query.Size)
.Take(query.Size)
.AsNoTracking()
.Select(u => new UserSummary(
u.Id,
u.Email,
u.IsActive
))
.ToListAsync(ct);

return new Paginated<UserSummary>(
items,
query.Page,
query.Size,
total
);
}



AsQueryable() чтобы можно было постепенно навешивать фильтры.

• Фильтрация по Q делается в базе, а не в памяти. Email и Name фильтруются прямо в SQL.

​• CountAsync считает Total для уже отфильтрованного набора, без Skip/Take. Это количество строк, которые удовлетворяют фильтрам.

Skip и Take делают пагинацию на стороне БД через OFFSET / FETCH или аналог, а не в памяти приложения.

AsNoTracking() говорит EF Core не отслеживать сущности в change tracker, что ускоряет чистые запросы на чтение.

Select сразу проецирует в UserSummary EF не создаёт полноценные сущности, не подгружает лишние поля и не собирает сложные графы.

Всё это превращается в один адекватный SQL запрос, а не в серию SELECT * плюс ручная фильтрация и подсчёты.

Паттерн пагинации это не про сложность, а наоборот про простоту и предсказуемость. Отдельные DTO, контейнер Paginated<T>, один явный запрос с фильтрами, подсчётом и AsNoTracking() дают API, которое не врёт клиенту, хорошо масштабируется и остаётся читабельным через год.

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🏆 Подборка топ-вакансий для шарпистов за неделю

C#/.NET-разработчикот 200 000 ₽ и удалёнка.

Senior .NET Engineer до 5 000 $ на гибрид в Минске.

Senior .NET Software Engineer до 7 000 $ удалённо. С такими деньгами легко можно попасть в топ 3% разрабов по ЗП.

Бустер — Удалённо (в любом городе мира).

➡️ Еще больше топовых вакансий — в нашем канале C# Jobs

🐸 Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🎁 Письмо Деду Морозу

До Нового Года 15 дней! Что бы вы хотели получить в подарок? Годовая премия не в счёт, это всегда как рулетка — повезёт/не повезёт.

Админ хотел бы набор оперативной памяти, желательно гига 32, откладывал до последнего и вот итог..

💬 Делитесь своими хотелками или сразу вишлистами в комментах 👇

📍 Навигация: ВакансииЗадачиСобесы

🐸Библиотека шарписта

#entry_point

Читать полностью…
Subscribe to a channel