⚡️ .NET: валидация Minimal API
В .NET 8 Preview 3 появилась встроенная поддержка валидации для Minimal API — теперь можно использовать атрибуты Required, Range, StringLength и другие прямо в минималистичных контроллерах без лишнего кода.
⚙️ Microsoft добавила официальный пример:
🔗 github.com/captainsafia/minapi-validation-support
🧪 В проекте показано:
- как включить AddValidation() в Program.cs
- как использовать
- как обрабатывать ошибки валидации автоматически
🚀 Чтобы запустить пример:
✍️ Минимализм + строгая валидация = 🔥 для API!
📌 Github
@csharp_1001_notes
В .NET 8 Preview 3 появилась встроенная поддержка валидации для Minimal API — теперь можно использовать атрибуты Required, Range, StringLength и другие прямо в минималистичных контроллерах без лишнего кода.
⚙️ Microsoft добавила официальный пример:
🔗 github.com/captainsafia/minapi-validation-support
🧪 В проекте показано:
- как включить AddValidation() в Program.cs
- как использовать
[ValidatableType]
для ваших моделей- как обрабатывать ошибки валидации автоматически
🚀 Чтобы запустить пример:
cd api
dotnet run
✍️ Минимализм + строгая валидация = 🔥 для API!
📌 Github
@csharp_1001_notes
🔧 Задача на C# для внимательных разработчиков
Что выведет следующий код?
Варианты ответа:
A)
B)
C)
D)
---
✅ Правильный ответ:B
Почему:
Лямбда-функции захватывают переменную по ссылке, а не её значение на каждой итерации. После завершения цикла , и все замыкания ссылаются на одно и то же . Это классическая ловушка замыканий в C#.
Что выведет следующий код?
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
actions.Add(() => Console.WriteLine(i));
}
foreach (var action in actions)
action();
}
}
Варианты ответа:
A)
1
2
B)
3
3
C)
0
0
D)
---
✅ Правильный ответ:
Почему:
Лямбда-функции захватывают переменную
i
i == 3
i
В третьем предварительном выпуске .NET 10 Preview 3, Microsoft сосредоточила внимание на улучшении производительности, удобстве для разработчиков и современных облачных паттернах.
Хотя этот выпуск не содержит значимых новых функций, он предлагает значительные усовершенствования в различных областях.
🔧 Основные нововведения
🐳 Нативная публикация контейнеров для консольных приложений
Теперь консольные приложения могут создавать контейнерные образы с помощью команды:
Это стало возможным без необходимости устанавливать свойство <EnableSdkContainerSupport> в значение true в файле проекта. Если требуется отключить эту поддержку, можно установить это свойство в false.
📦 Управление форматом контейнерных образов
Разработчики получили возможность явно указывать формат контейнерного образа (.Docker или .OCI) с помощью нового свойства <ContainerImageFormat> в SDK. По умолчанию SDK выбирает формат на основе архитектуры контейнера и базового образа, но теперь это поведение можно переопределить, что особенно полезно для команд, стандартизирующихся на формате OCI.
🌐 Обновления для облачных и веб-приложений
ASP.NET Core: Добавлена поддержка OpenAPI 3.1, что обеспечивает лучшую интеграцию с современными API-шлюзами и инструментами проектирования. Также теперь можно обслуживать документы OpenAPI в формате YAML, что широко используется в инфраструктуре как код и DevOps-процессах.
Blazor Web Apps: Введён новый компонент ReconnectModal для более плавной обработки отключений клиента. Улучшения также коснулись компонента QuickGrid, включая условное стилизование строк и управление пользовательским интерфейсом. Навигация стала более предсказуемой, избегая ненужной прокрутки страниц и лучше обрабатывая строки запроса. Кроме того, скрипт фреймворка Blazor теперь обслуживается как статический веб-ресурс с отпечатком, улучшая кэширование и производительность, особенно в средах с CDN или на периферии сети.
⚙️ Дополнительные улучшения
Оптимизация SDK: Автоматическое удаление неиспользуемых ссылок на пакеты, предоставляемые фреймворком, что снижает использование диска и улучшает производительность сборки.
- Улучшения CLI:
Введены новые алиасы команд, такие как dotnet package add, для повышения ясности и согласованности командной строки.
Теперь можно генерировать скрипты автодополнения оболочки с помощью команды dotnet completions generate <SHELL> для bash, zsh, powershell и других.
В интерактивных терминалах команды CLI теперь по умолчанию работают в интерактивном режиме, упрощая взаимодействие с пользователем.
- Улучшения JIT-компилятора:
Возможность деинлайнить и инлайнить методы интерфейса на массивах, улучшая производительность в коде с интенсивным использованием коллекций.
Оптимизация перечисления массивов, позволяющая лучшую инлайнизацию JIT и размещение в стеке.
Поддержка инлайнинга методов, которые становятся деинлайненными после предыдущих шагов инлайнинга.
Разрешение размещения в стеке для небольших массивов фиксированного размера, состоящих из типов значений без указателей GC, снижая нагрузку на кучу.
- Новые API и улучшения:
Поддержка поиска сертификатов по отпечатку с использованием алгоритмов, отличных от SHA-1, таких как SHA-256.
Улучшения в кодировании PEM: API PEM теперь поддерживают чтение ASCII/UTF-8 текста напрямую, упрощая кроссплатформенную работу с ключами и сертификатами.
Поддержка DateOnly в ISOWeek: новые перегрузки для работы со значениями DateOnly в логике, основанной на неделях.
Нормализация строк для Span<char> и ReadOnlySpan<char>: новые API позволяют выполнять нормализацию Unicode напрямую на этих типах, снижая количество выделений памяти.
Для получения более подробной информации сюда
Хотя этот выпуск не содержит значимых новых функций, он предлагает значительные усовершенствования в различных областях.
🔧 Основные нововведения
🐳 Нативная публикация контейнеров для консольных приложений
Теперь консольные приложения могут создавать контейнерные образы с помощью команды:
dotnet publish /t:PublishContainer
Это стало возможным без необходимости устанавливать свойство <EnableSdkContainerSupport> в значение true в файле проекта. Если требуется отключить эту поддержку, можно установить это свойство в false.
📦 Управление форматом контейнерных образов
Разработчики получили возможность явно указывать формат контейнерного образа (.Docker или .OCI) с помощью нового свойства <ContainerImageFormat> в SDK. По умолчанию SDK выбирает формат на основе архитектуры контейнера и базового образа, но теперь это поведение можно переопределить, что особенно полезно для команд, стандартизирующихся на формате OCI.
🌐 Обновления для облачных и веб-приложений
ASP.NET Core: Добавлена поддержка OpenAPI 3.1, что обеспечивает лучшую интеграцию с современными API-шлюзами и инструментами проектирования. Также теперь можно обслуживать документы OpenAPI в формате YAML, что широко используется в инфраструктуре как код и DevOps-процессах.
Blazor Web Apps: Введён новый компонент ReconnectModal для более плавной обработки отключений клиента. Улучшения также коснулись компонента QuickGrid, включая условное стилизование строк и управление пользовательским интерфейсом. Навигация стала более предсказуемой, избегая ненужной прокрутки страниц и лучше обрабатывая строки запроса. Кроме того, скрипт фреймворка Blazor теперь обслуживается как статический веб-ресурс с отпечатком, улучшая кэширование и производительность, особенно в средах с CDN или на периферии сети.
⚙️ Дополнительные улучшения
Оптимизация SDK: Автоматическое удаление неиспользуемых ссылок на пакеты, предоставляемые фреймворком, что снижает использование диска и улучшает производительность сборки.
- Улучшения CLI:
Введены новые алиасы команд, такие как dotnet package add, для повышения ясности и согласованности командной строки.
Теперь можно генерировать скрипты автодополнения оболочки с помощью команды dotnet completions generate <SHELL> для bash, zsh, powershell и других.
В интерактивных терминалах команды CLI теперь по умолчанию работают в интерактивном режиме, упрощая взаимодействие с пользователем.
- Улучшения JIT-компилятора:
Возможность деинлайнить и инлайнить методы интерфейса на массивах, улучшая производительность в коде с интенсивным использованием коллекций.
Оптимизация перечисления массивов, позволяющая лучшую инлайнизацию JIT и размещение в стеке.
Поддержка инлайнинга методов, которые становятся деинлайненными после предыдущих шагов инлайнинга.
Разрешение размещения в стеке для небольших массивов фиксированного размера, состоящих из типов значений без указателей GC, снижая нагрузку на кучу.
- Новые API и улучшения:
Поддержка поиска сертификатов по отпечатку с использованием алгоритмов, отличных от SHA-1, таких как SHA-256.
Улучшения в кодировании PEM: API PEM теперь поддерживают чтение ASCII/UTF-8 текста напрямую, упрощая кроссплатформенную работу с ключами и сертификатами.
Поддержка DateOnly в ISOWeek: новые перегрузки для работы со значениями DateOnly в логике, основанной на неделях.
Нормализация строк для Span<char> и ReadOnlySpan<char>: новые API позволяют выполнять нормализацию Unicode напрямую на этих типах, снижая количество выделений памяти.
Для получения более подробной информации сюда
Вы используете локальные переменные в LINQ и используете let? 👇
Ключевое слово let позволяет вводить временную переменную прямо внутри запроса LINQ — как локальную переменную в цикле.
Разбивайте сложные вычисления на части
Делайте запрос модульнее и чище
Меньше проходов по данным → выше производительность
👉 Простой пример:
csharp
Ключевое слово let позволяет вводить временную переменную прямо внутри запроса LINQ — как локальную переменную в цикле.
Разбивайте сложные вычисления на части
Делайте запрос модульнее и чище
Меньше проходов по данным → выше производительность
👉 Простой пример:
csharp
from order in orders
let total = order.Items.Sum(i => i.Price * i.Quantity)
where total > 1000
let categories = order.Items.Select(i => i.Category).Distinct()
select new
{
OrderId = order.Id,
Total = total,
Categories = categories
};
let total
= … — вычисляем сумму заказа только один разwhere total >
1000 — фильтруем по готовому значениюlet categories =
… — собираем уникальные категории⚡️Легкий способ получать свежие обновления и следить за трендами в разработке на вашем языке. Находите свой стек и подписывайтесь:
Python: www.tg-me.com/pythonl
Linux: www.tg-me.com/linuxacademiya
Собеседования DS: www.tg-me.com/machinelearning_interview
Нерйросети www.tg-me.com/ai_machinelearning_big_data
C++ www.tg-me.com/cpluspluc
Docker: www.tg-me.com/DevopsDocker
Хакинг: www.tg-me.com/linuxkalii
Devops: www.tg-me.com/DevOPSitsec
Data Science: www.tg-me.com/data_analysis_ml
Javascript: www.tg-me.com/javascriptv
C#: www.tg-me.com/csharp_ci
Java: www.tg-me.com/javatg
Базы данных: www.tg-me.com/sqlhub
Python собеседования: www.tg-me.com/python_job_interview
Мобильная разработка: www.tg-me.com/mobdevelop
Golang: www.tg-me.com/Golang_google
React: www.tg-me.com/react_tg
Rust: www.tg-me.com/rust_code
ИИ: www.tg-me.com/vistehno
PHP: www.tg-me.com/phpshka
Android: www.tg-me.com/android_its
Frontend: www.tg-me.com/front
Big Data: www.tg-me.com/bigdatai
МАТЕМАТИКА: www.tg-me.com/data_math
Kubernets: www.tg-me.com/kubernetc
Разработка игр: https://www.tg-me.com/gamedev
Haskell: www.tg-me.com/haskell_tg
Физика: www.tg-me.com/fizmat
💼 Папка с вакансиями: www.tg-me.com/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: www.tg-me.com/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: www.tg-me.com/addlist/eEPya-HF6mkxMGIy
Папка ML: https://www.tg-me.com/addlist/2Ls-snqEeytkMDgy
Папка FRONTEND: https://www.tg-me.com/addlist/mzMMG3RPZhY2M2Iy
😆ИТ-Мемы: www.tg-me.com/memes_prog
🇬🇧Английский: www.tg-me.com/english_forprogrammers
🧠ИИ: www.tg-me.com/vistehno
🎓954ГБ ОПЕНСОРС КУРСОВ: @courses
📕Ит-книги бесплатно: https://www.tg-me.com/addlist/BkskQciUW_FhNjEy
Python: www.tg-me.com/pythonl
Linux: www.tg-me.com/linuxacademiya
Собеседования DS: www.tg-me.com/machinelearning_interview
Нерйросети www.tg-me.com/ai_machinelearning_big_data
C++ www.tg-me.com/cpluspluc
Docker: www.tg-me.com/DevopsDocker
Хакинг: www.tg-me.com/linuxkalii
Devops: www.tg-me.com/DevOPSitsec
Data Science: www.tg-me.com/data_analysis_ml
Javascript: www.tg-me.com/javascriptv
C#: www.tg-me.com/csharp_ci
Java: www.tg-me.com/javatg
Базы данных: www.tg-me.com/sqlhub
Python собеседования: www.tg-me.com/python_job_interview
Мобильная разработка: www.tg-me.com/mobdevelop
Golang: www.tg-me.com/Golang_google
React: www.tg-me.com/react_tg
Rust: www.tg-me.com/rust_code
ИИ: www.tg-me.com/vistehno
PHP: www.tg-me.com/phpshka
Android: www.tg-me.com/android_its
Frontend: www.tg-me.com/front
Big Data: www.tg-me.com/bigdatai
МАТЕМАТИКА: www.tg-me.com/data_math
Kubernets: www.tg-me.com/kubernetc
Разработка игр: https://www.tg-me.com/gamedev
Haskell: www.tg-me.com/haskell_tg
Физика: www.tg-me.com/fizmat
💼 Папка с вакансиями: www.tg-me.com/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: www.tg-me.com/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: www.tg-me.com/addlist/eEPya-HF6mkxMGIy
Папка ML: https://www.tg-me.com/addlist/2Ls-snqEeytkMDgy
Папка FRONTEND: https://www.tg-me.com/addlist/mzMMG3RPZhY2M2Iy
😆ИТ-Мемы: www.tg-me.com/memes_prog
🇬🇧Английский: www.tg-me.com/english_forprogrammers
🧠ИИ: www.tg-me.com/vistehno
🎓954ГБ ОПЕНСОРС КУРСОВ: @courses
📕Ит-книги бесплатно: https://www.tg-me.com/addlist/BkskQciUW_FhNjEy
📌 Задача: "Высоконагружённый кэш с автоматической очисткой и конкурентным доступом"
❗️Условие:
Реализуйте класс
- Позволять безопасно добавлять и получать элементы из кэша в многопоточной среде (`Get`, `Set`).
- Автоматически удалять элементы через N секунд после их добавления (TTL).
- Поддерживать высокую производительность при массовом доступе (тысячи операций в секунду).
- Минимизировать блокировки (`lock`) или использовать неблокирующие структуры.
- Корректно работать с истекшими элементами:
- Не возвращать их через
- Не копить мусор в памяти.
---
▪️ Ограничения:
- Можно использовать стандартные коллекции .NET (`ConcurrentDictionary`,
- Нельзя использовать внешние библиотеки типа
- Нужно поддерживать работу под большой нагрузкой (много ключей и операций параллельно).
---
▪️ Подсказки:
- Для конкурентного доступа подойдёт
- Для очистки устаревших данных:
- Можно использовать фоновую задачу (`Task`) с таймером, которая периодически чистит старые записи.
- Обратите внимание на гонки состояний: между проверкой срока жизни элемента и его удалением.
---
▪️ Что оценивается:
- Умение проектировать потокобезопасные структуры данных.
- Продуманность балансировки между скоростью операций и частотой очистки.
- Правильная работа со временем жизни (`TTL`).
- Чистота и лаконичность кода.
---
▪️ Разбор возможного решения:
▪️ Основная идея:
- В кэше храним не просто значение, а пару (значение + время истечения).
- При
- Проверяем, истёк ли элемент.
- Если истёк — удаляем его и возвращаем
- При
- Сохраняем значение с текущим временем + TTL.
- Отдельная фоновая задача (`Task`) регулярно сканирует кэш и удаляет устаревшие элементы.
▪️ Мини-пример структуры:
📌 Важные моменты:
- Кэш конкурентный (`ConcurrentDictionary`) — доступ без явных блокировок.
- Периодическая чистка не мешает основным операциям.
- Удаление истёкших элементов происходит "мягко" (через проверку срока жизни).
- Фоновая задача корректно завершается через
❗️Условие:
Реализуйте класс
SmartCache<TKey, TValue>
в .NET, который должен:- Позволять безопасно добавлять и получать элементы из кэша в многопоточной среде (`Get`, `Set`).
- Автоматически удалять элементы через N секунд после их добавления (TTL).
- Поддерживать высокую производительность при массовом доступе (тысячи операций в секунду).
- Минимизировать блокировки (`lock`) или использовать неблокирующие структуры.
- Корректно работать с истекшими элементами:
- Не возвращать их через
Get
.- Не копить мусор в памяти.
---
▪️ Ограничения:
- Можно использовать стандартные коллекции .NET (`ConcurrentDictionary`,
Timer
, Task
, CancellationToken
и т.д.).- Нельзя использовать внешние библиотеки типа
MemoryCache
, Redis
, LazyCache
и др.- Нужно поддерживать работу под большой нагрузкой (много ключей и операций параллельно).
---
▪️ Подсказки:
- Для конкурентного доступа подойдёт
ConcurrentDictionary<TKey, ValueWithExpiry>
.- Для очистки устаревших данных:
- Можно использовать фоновую задачу (`Task`) с таймером, которая периодически чистит старые записи.
- Обратите внимание на гонки состояний: между проверкой срока жизни элемента и его удалением.
---
▪️ Что оценивается:
- Умение проектировать потокобезопасные структуры данных.
- Продуманность балансировки между скоростью операций и частотой очистки.
- Правильная работа со временем жизни (`TTL`).
- Чистота и лаконичность кода.
---
▪️ Разбор возможного решения:
▪️ Основная идея:
- В кэше храним не просто значение, а пару (значение + время истечения).
- При
Get(key)
:- Проверяем, истёк ли элемент.
- Если истёк — удаляем его и возвращаем
null
или default
.- При
Set(key, value)
:- Сохраняем значение с текущим временем + TTL.
- Отдельная фоновая задача (`Task`) регулярно сканирует кэш и удаляет устаревшие элементы.
▪️ Мини-пример структуры:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class SmartCache<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, (TValue Value, DateTime Expiry)> _cache = new();
private readonly TimeSpan _ttl;
private readonly CancellationTokenSource _cts = new();
public SmartCache(TimeSpan ttl)
{
_ttl = ttl;
StartCleanupTask();
}
public void Set(TKey key, TValue value)
{
_cache[key] = (value, DateTime.UtcNow.Add(_ttl));
}
public TValue Get(TKey key)
{
if (_cache.TryGetValue(key, out var entry))
{
if (entry.Expiry > DateTime.UtcNow)
{
return entry.Value;
}
else
{
_cache.TryRemove(key, out _);
}
}
return default;
}
private void StartCleanupTask()
{
Task.Run(async () =>
{
while (!_cts.Token.IsCancellationRequested)
{
foreach (var key in _cache.Keys)
{
if (_cache.TryGetValue(key, out var entry) && entry.Expiry <= DateTime.UtcNow)
{
_cache.TryRemove(key, out _);
}
}
await Task.Delay(TimeSpan.FromSeconds(30), _cts.Token); // периодическая очистка
}
});
}
public void Dispose()
{
_cts.Cancel();
}
}
📌 Важные моменты:
- Кэш конкурентный (`ConcurrentDictionary`) — доступ без явных блокировок.
- Периодическая чистка не мешает основным операциям.
- Удаление истёкших элементов происходит "мягко" (через проверку срока жизни).
- Фоновая задача корректно завершается через
CancellationToken
.Forwarded from C# (C Sharp) programming
🚀 Silk.NET 3.0: грядущая революция в .NET-графике
Сообщество Silk.NET анонсировало работу над третьей версией своего фреймворка — амбициозным переосмыслением того, как должны работать низкоуровневые .NET-биндинги для графики и мультимедиа.
Особенность проекта всегда заключалась в кроссплатформенности и минимальных накладных расходах при работе с GPU. В 3.0 разработчики обещают переработанную систему биндингов и улучшенную интеграцию с современными .NET-стэками.
🤖 GitHub
@csharp_ci
Сообщество Silk.NET анонсировало работу над третьей версией своего фреймворка — амбициозным переосмыслением того, как должны работать низкоуровневые .NET-биндинги для графики и мультимедиа.
Особенность проекта всегда заключалась в кроссплатформенности и минимальных накладных расходах при работе с GPU. В 3.0 разработчики обещают переработанную систему биндингов и улучшенную интеграцию с современными .NET-стэками.
🤖 GitHub
@csharp_ci
🧠 Задача на C#: "Сбалансированное стандартное отклонение"
Условие
Дан список чисел
Нужно определить: существует ли такой индекс, при котором массив можно разделить на две части, и стандартные отклонения этих частей отличаются не более чем на `epsilon` (например, 0.1).
Пример:
Формат функции:
Решение:
Пример использования:
Что проверяет задача:
• знание статистики и работы со стандартным отклонением
• навыки эффективной работы с коллекциями
• аккуратность при вычислениях с
• понимание требований к длине выборки для корректной статистики
@csharp_1001_notes
Условие
Дан список чисел
List<double>
— это одномерное распределение значений. Нужно определить: существует ли такой индекс, при котором массив можно разделить на две части, и стандартные отклонения этих частей отличаются не более чем на `epsilon` (например, 0.1).
Пример:
var data = new List<double> { 1.0, 2.0, 3.0, 6.0, 9.0 };
// Разделение после 2 → [1.0, 2.0], [3.0, 6.0, 9.0]
// std_left ≈ 0.707, std_right ≈ 3.0 → ❌ слишком большая разница
Формат функции:
public static bool HasBalancedStdSplit(List<double> data, double epsilon = 0.1)
Решение:
using System;
using System.Collections.Generic;
using System.Linq;
public class StatUtils
{
public static bool HasBalancedStdSplit(List<double> data, double epsilon = 0.1)
{
int n = data.Count;
if (n < 4) return false;
for (int i = 2; i <= n - 2; i++)
{
var left = data.Take(i).ToList();
var right = data.Skip(i).ToList();
double stdLeft = StandardDeviation(left);
double stdRight = StandardDeviation(right);
if (Math.Abs(stdLeft - stdRight) <= epsilon)
return true;
}
return false;
}
private static double StandardDeviation(List<double> values)
{
double mean = values.Average();
double sumSquares = values.Sum(v => Math.Pow(v - mean, 2));
return Math.Sqrt(sumSquares / (values.Count - 1));
}
}
Пример использования:
class Program
{
static void Main()
{
var data = new List<double> { 2, 4, 4, 4, 5, 5, 7, 9 };
bool result = StatUtils.HasBalancedStdSplit(data, 0.5);
Console.WriteLine($"Можно ли сбалансировать: {result}");
}
}
Что проверяет задача:
• знание статистики и работы со стандартным отклонением
• навыки эффективной работы с коллекциями
• аккуратность при вычислениях с
double
• понимание требований к длине выборки для корректной статистики
@csharp_1001_notes
⚙️ `[EnumeratorCancellation]` в C# — критически важный атрибут для корректной отмены в `IAsyncEnumerable`
В .NET асинхронные итераторы (`IAsyncEnumerable<T>`) стали мощным инструментом для потоковой обработки данных. Но если вы используете
⚠️ Проблема: токен есть, но он бесполезен
Допустим, вы пишете такой метод:
Выглядит нормально, но есть подвох: при отмене токен не передаётся в `MoveNextAsync()`, то есть итерация может продолжаться, даже если вызвавшая сторона уже вызвала
💣 Последствия
• Фоновая загрузка продолжается после отмены
• Зависшие соединения, неосвобождённые ресурсы
• Непредсказуемое поведение в
• Сложные баги и плохая отзывчивость приложений
✅ Решение:
Правильно будет вот так:
📌 Атрибут
🧪 Как проверить
Если метод реализован без
Если с атрибутом — отмена сработает как положено, и итерация завершится немедленно.
🛠 Best Practices
✔ Всегда используйте
✔ Внутри итератора:
- Вызывайте
- Оборачивайте вложенные
✔ Не используйте токен «для галочки» — он должен влиять на поведение итератора
✔ Добавляйте юнит‑тесты на отмену, особенно если вы работаете с I/O, API или базами данных
📎 Заключение
Асинхронные итераторы — мощь. Но без
Одна строка — и вы защищены:
📚 Источник: https://bartwullems.blogspot.com/2025/04/asyncenumerable-in-c-importance-of.html
🧠 Если ты пишешь на C# и используешь
📌 Читать
@csharp_1001_notes
В .NET асинхронные итераторы (`IAsyncEnumerable<T>`) стали мощным инструментом для потоковой обработки данных. Но если вы используете
CancellationToken
без специального атрибута [EnumeratorCancellation]
, ваш код может вести себя некорректно и утекать ресурсы. Разберёмся подробно.⚠️ Проблема: токен есть, но он бесполезен
Допустим, вы пишете такой метод:
public async IAsyncEnumerable<string> FetchItems(CancellationToken cancellationToken)
{
foreach (var id in ids)
{
var item = await GetDataAsync(id);
yield return item;
}
}
Выглядит нормально, но есть подвох: при отмене токен не передаётся в `MoveNextAsync()`, то есть итерация может продолжаться, даже если вызвавшая сторона уже вызвала
cancellationToken.Cancel()
.💣 Последствия
• Фоновая загрузка продолжается после отмены
• Зависшие соединения, неосвобождённые ресурсы
• Непредсказуемое поведение в
await foreach
• Сложные баги и плохая отзывчивость приложений
✅ Решение:
[EnumeratorCancellation]
Правильно будет вот так:
public async IAsyncEnumerable<string> FetchItems(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var item in LoadFromDb().WithCancellation(cancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
yield return item;
}
}
📌 Атрибут
[EnumeratorCancellation]
сообщает компилятору, что токен должен быть передан в реализацию `MoveNextAsync()` итератора. Без этого атрибута токен проигнорируется.🧪 Как проверить
var cts = new CancellationTokenSource();
await foreach (var item in FetchItems(cts.Token))
{
if (item == "stop") cts.Cancel();
}
Если метод реализован без
[EnumeratorCancellation]
, цикл может не остановиться. Если с атрибутом — отмена сработает как положено, и итерация завершится немедленно.
🛠 Best Practices
✔ Всегда используйте
[EnumeratorCancellation]
, если метод IAsyncEnumerable<T>
принимает CancellationToken
✔ Внутри итератора:
- Вызывайте
ThrowIfCancellationRequested()
- Оборачивайте вложенные
await foreach
или асинхронные методы в .WithCancellation(token)
✔ Не используйте токен «для галочки» — он должен влиять на поведение итератора
✔ Добавляйте юнит‑тесты на отмену, особенно если вы работаете с I/O, API или базами данных
📎 Заключение
Асинхронные итераторы — мощь. Но без
[EnumeratorCancellation]
ваш токен отмены просто не работает. И это не очевидно, пока вы не столкнётесь с багом, когда ресурсы не освобождаются, или цикл не завершается.Одна строка — и вы защищены:
[EnumeratorCancellation] CancellationToken token
📚 Источник: https://bartwullems.blogspot.com/2025/04/asyncenumerable-in-c-importance-of.html
🧠 Если ты пишешь на C# и используешь
IAsyncEnumerable
— знай: токен без атрибута = фейковая отмена.📌 Читать
@csharp_1001_notes
Горизонтальное масштабирование СУБД на примере Greenplum
Современные приложения работают с огромными объёмами данных, и рано или поздно классические СУБД перестают справляться с нагрузкой. Выход — горизонтальное масштабирование, позволяющее эффективно распределять запросы и хранение по нескольким узлам.
📌 На вебинары вы:
— Познакомитесь с концепцией горизонтального масштабирования и почему оно критически важно в высоконагруженных системах.
— Разберёте архитектуру СУБД Greenplum — одного из самых мощных решений на базе PostgreSQL для работы с Big Data.
— Узнаете, как устроены шардирование, партиционирование, репликация и управление кластерами в Greenplum.
— Посмотрите реальные кейсы использования Greenplum в распределённых системах.
👉 Регистрация и подробности о курсе Highload Architect: https://otus.pw/zwUN/?erid=2W5zFGGPcs2
Бесплатное занятие приурочено к старту курса Highload Architect, обучение на котором позволит освоить решения, которые выдерживают большое количество запросов в секунду и правильно оптимизировать работоспособность серверов.
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.
Современные приложения работают с огромными объёмами данных, и рано или поздно классические СУБД перестают справляться с нагрузкой. Выход — горизонтальное масштабирование, позволяющее эффективно распределять запросы и хранение по нескольким узлам.
📌 На вебинары вы:
— Познакомитесь с концепцией горизонтального масштабирования и почему оно критически важно в высоконагруженных системах.
— Разберёте архитектуру СУБД Greenplum — одного из самых мощных решений на базе PostgreSQL для работы с Big Data.
— Узнаете, как устроены шардирование, партиционирование, репликация и управление кластерами в Greenplum.
— Посмотрите реальные кейсы использования Greenplum в распределённых системах.
Бесплатное занятие приурочено к старту курса Highload Architect, обучение на котором позволит освоить решения, которые выдерживают большое количество запросов в секунду и правильно оптимизировать работоспособность серверов.
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.
Please open Telegram to view this post
VIEW IN TELEGRAM
🧠 C# Задача: “Ловушка замыкания в цикле”
📜 Условие:
Посмотри на этот код и скажи, что он выведет:
❓ Вопросы:
1. Что напечатает программа?
2. Почему результат может удивить?
3. Как исправить код, чтобы получить
⚠️ Подвох:
- Переменная
- Когда цикл завершится,
---
### ✅ Ожидаемый вывод:
🛠️ Исправление:
Чтобы каждая лямбда захватывала свою копию `i`, нужно добавить промежуточную переменную:
Теперь вывод будет:
🎯 Что проверяет задача:
- Знание механики замыканий в C#
- Понимание разницы между значениями и ссылками в замыкании
- Умение отлаживать неожиданные результаты в LINQ и делегатах
📜 Условие:
Посмотри на этот код и скажи, что он выведет:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
var actions = new List<Action>();
for (int i = 0; i < 5; i++)
{
actions.Add(() => Console.Write(i + " "));
}
foreach (var action in actions)
{
action();
}
}
}
❓ Вопросы:
1. Что напечатает программа?
2. Почему результат может удивить?
3. Как исправить код, чтобы получить
0 1 2 3 4
?⚠️ Подвох:
- Переменная
i
захватывается по ссылке всеми лямбдами в List<Action>
, а не копируется в момент добавления.- Когда цикл завершится,
i == 5
, и все лямбды обращаются к одному и тому же `i`, уже равному 5
.---
### ✅ Ожидаемый вывод:
5 5 5 5 5
🛠️ Исправление:
Чтобы каждая лямбда захватывала свою копию `i`, нужно добавить промежуточную переменную:
for (int i = 0; i < 5; i++)
{
int copy = i;
actions.Add(() => Console.Write(copy + " "));
}
Теперь вывод будет:
0 1 2 3 4
🎯 Что проверяет задача:
- Знание механики замыканий в C#
- Понимание разницы между значениями и ссылками в замыкании
- Умение отлаживать неожиданные результаты в LINQ и делегатах
Разработчики, девопсы, сисадмины: 📲 внимание, внимание!
Похоже, эпоха открытого исходного кода идёт к концу: одна за одной наши любимые бесплатные C#-библиотеки становятся платными. И что же теперь делать? Давайте соберёмся вместе и подумаем.
Приглашаем вас на открытую онлайн-дискуссию «Библиотеки C# уходят в платную сферу: конец эры опенсорса?»
📌Узнаете, какие библиотеки уже стали платными и что ждёт экосистему дальше
📌Узнаете, чем конкретно можно заменить ту или иную библиотеку
📌Сможете уменьшить лицензионные риски
📌Сможете вовремя изменить карьерный вектор или поменять архитектуру проектов
📌 Получите экспертные рекомендации по архитектуре и устойчивым решениям
Спикеры:
👨💻Олег Голенищев – старший разработчик в Directum
👨💻Антон Герасименко – ведущий .NET-разработчик.
Всем участникам – скидка 7% на любой курс OTUS и подборка альтернативных библиотек с открытым исходным кодом в подарок.
27 мая, 19:00 МСК
Бесплатно по записи: https://tglink.io/a87663fba48d
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. erid: 2W5zFG9Ybix
Похоже, эпоха открытого исходного кода идёт к концу: одна за одной наши любимые бесплатные C#-библиотеки становятся платными. И что же теперь делать? Давайте соберёмся вместе и подумаем.
Приглашаем вас на открытую онлайн-дискуссию «Библиотеки C# уходят в платную сферу: конец эры опенсорса?»
📌Узнаете, какие библиотеки уже стали платными и что ждёт экосистему дальше
📌Узнаете, чем конкретно можно заменить ту или иную библиотеку
📌Сможете уменьшить лицензионные риски
📌Сможете вовремя изменить карьерный вектор или поменять архитектуру проектов
📌 Получите экспертные рекомендации по архитектуре и устойчивым решениям
Спикеры:
👨💻Олег Голенищев – старший разработчик в Directum
👨💻Антон Герасименко – ведущий .NET-разработчик.
Всем участникам – скидка 7% на любой курс OTUS и подборка альтернативных библиотек с открытым исходным кодом в подарок.
27 мая, 19:00 МСК
Бесплатно по записи: https://tglink.io/a87663fba48d
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. erid: 2W5zFG9Ybix
🚀 Wissance.WebApiToolkit: Быстрое создание REST и GRPC API на .NET
Если устал каждый раз писать одинаковый CRUD — этот toolkit тебя спасёт.
С помощью [Wissance.WebApiToolkit](https://github.com/Wissance/WebApiToolkit) можно создать полноценный REST или GRPC API почти без усилий.
● Что умеет:
- Минимум кода — CRUD-контроллер ≈ 10 строк
- BULK-операции: обновление/удаление сразу нескольких объектов
- Поддержка Entity Framework, EdgeDB и других хранилищ через
- Автогенерация GRPC-сервисов
- Встроенная пагинация, фильтрация, сортировка
- Поддержка Swagger (c версии 1.6.0)
● Архитектура построена на 5 слоях:
● Пример CRUD-контроллера:
● Установка:
🔗 WeatherControl — полная интеграция с EF и EdgeDB
⭐ Проект open-source:
github.com/Wissance/WebApiToolkit
Если устал каждый раз писать одинаковый CRUD — этот toolkit тебя спасёт.
С помощью [Wissance.WebApiToolkit](https://github.com/Wissance/WebApiToolkit) можно создать полноценный REST или GRPC API почти без усилий.
● Что умеет:
- Минимум кода — CRUD-контроллер ≈ 10 строк
- BULK-операции: обновление/удаление сразу нескольких объектов
- Поддержка Entity Framework, EdgeDB и других хранилищ через
IModelManager
- Автогенерация GRPC-сервисов
- Встроенная пагинация, фильтрация, сортировка
- Поддержка Swagger (c версии 1.6.0)
● Архитектура построена на 5 слоях:
Entity
→ DTO
→ Factory
→ Manager
→ Controller
● Пример CRUD-контроллера:
[ApiController]
public class BookController : BasicCrudController<BookDto, BookEntity, int, EmptyAdditionalFilters>
{
public BookController(BookManager manager)
{
Manager = manager;
_manager = manager;
}
private readonly BookManager _manager;
}
● Установка:
dotnet add package Wissance.WebApiToolkit
🔗 WeatherControl — полная интеграция с EF и EdgeDB
⭐ Проект open-source:
github.com/Wissance/WebApiToolkit
ХОЧЕШЬ ПОВЫСИТЬ ГРЕЙД В 2025 ГОДУ? 🚀
Чтобы стать Senior C# разработчиком сегодня, нужно не только знать язык программирования и фреймворки. Нужно уметь строить гибкую архитектуру приложения, которую легко тестировать и менять под задачи бизнеса. Стань экспертом в построении гибкой архитектуры приложения!
👉 Стартуем 2 июня.
Курс ведет действующий архитектор и Principal Engineer Кирилл Ветчинкин.
Ты научишься:
✅ Разбивать приложение на слои в соответствии с Clean Architecture
✅ Формировать Domain Model и применять тактические паттерны DDD
✅ Реализовывать Use Case как Command/Query
✅ Делать синхронные и асинхронные интеграции, не загрязняя ядро приложения
✅ Писать 3 вида тестов для разных слоев приложения
Полная программа ТУТ 👉 https://microarch.ru/courses/ddd?utm_source=posev&utm_medium=erid:2VtzqwTjbcd&utm_campaign=5
А главное — ты с нуля разработаешь и запустишь микросервис, который максимально приближен к реальности "Диспетчеризация заказов на курьеров". Это будет крутым проектом в портфолио или основой для рабочих задач.
А еще:
✅ Проверим все домашки
✅ Поддержим в чате
✅ Проведем живые разборы
✅ Ответим на все вопросы
📕 Сертификат об участии по итогам прохождения курса.
🔥 Не откладывай свой рост на потом: https://microarch.ru/courses/ddd?utm_source=posev&utm_medium=erid:2VtzqwTjbcd&utm_campaign=5
Реклама. ИП Ветчинкин К.Е. ИНН: 773376451099 Erid: 2VtzqwTjbcd
Чтобы стать Senior C# разработчиком сегодня, нужно не только знать язык программирования и фреймворки. Нужно уметь строить гибкую архитектуру приложения, которую легко тестировать и менять под задачи бизнеса. Стань экспертом в построении гибкой архитектуры приложения!
👉 Стартуем 2 июня.
Курс ведет действующий архитектор и Principal Engineer Кирилл Ветчинкин.
Ты научишься:
✅ Разбивать приложение на слои в соответствии с Clean Architecture
✅ Формировать Domain Model и применять тактические паттерны DDD
✅ Реализовывать Use Case как Command/Query
✅ Делать синхронные и асинхронные интеграции, не загрязняя ядро приложения
✅ Писать 3 вида тестов для разных слоев приложения
Полная программа ТУТ 👉 https://microarch.ru/courses/ddd?utm_source=posev&utm_medium=erid:2VtzqwTjbcd&utm_campaign=5
А главное — ты с нуля разработаешь и запустишь микросервис, который максимально приближен к реальности "Диспетчеризация заказов на курьеров". Это будет крутым проектом в портфолио или основой для рабочих задач.
А еще:
✅ Проверим все домашки
✅ Поддержим в чате
✅ Проведем живые разборы
✅ Ответим на все вопросы
📕 Сертификат об участии по итогам прохождения курса.
🔥 Не откладывай свой рост на потом: https://microarch.ru/courses/ddd?utm_source=posev&utm_medium=erid:2VtzqwTjbcd&utm_campaign=5
Реклама. ИП Ветчинкин К.Е. ИНН: 773376451099 Erid: 2VtzqwTjbcd
🔥 From C# to Rust: 42-дневный челлендж от Chris Woody Woodruff
Chris Woodruff, экспериментающий .NET-разработчик, объявил старт своего 42-дневного пути погружения в Rust — язык системного программирования, совмещающий производительность, безопасность и отсутствие null:contentReference[oaicite:0]{index=0}.
🎯 Цели проекта
- Жить и дышать Rust — по одному уроку в день.
- Противостоять строгому borrow checker.
- Осознанно учиться и делиться выводами от лица C#-разработчика.
🛠 Что ожидается изучить
- Владение памятью, шаблоны, трейты, времена жизни (`lifetimes`).
- Яркие сравнения Rust и C#: синтаксис, ownership vs GC, ошибки компилятора:contentReference[oaicite:2]{index=2}.
- Краткие ежедневные отражения из .NET-мира.
📅 Примерный план на 42 дня
1. День 1–7: Почему Rust? Установка, cargo new vs dotnet new, "Hello, World!", переменные, функции:contentReference[oaicite:4]{index=4}.
2. День 8–14: Неделя владения — темы: ownership, borrowing, borrow checker:contentReference[oaicite:5]{index=5}.
3. День 15–42: Структуры, перечисления (`enum`), match, Option<T>, Result<T, E>, модули, ошибки, трейты, дженерики, лямбды и многое другое.
💬 Голос из сообщества
> «What happens when a C# dev swaps null for Option, garbage collection for ownership… You get 42 days of brain‑bending, compiler‑fighting…»
✨ Подытожим
- Проект идёт с апреля 2025 года, уже опубликованы десятки дневных эссе.
- Каждая запись по мотивам реального опыта: «why won’t this compile?!», сравнения с привычным C#.
- В финале — обзор полученного опыта, личные инсайты и примеры рабочего CLI‑приложения на Rust:contentReference[oaicite:8]{index=8}.
🚀 Готовы бросить вызов себе и глубже понять Rust?
Следите за дневником Woody и за входом в мир безопасных без‑GC систем прямо с .NET-опытов!
🔗 Подробнее: From C# to Rust: A 42-Day Developer Challenge
https://woodruff.dev/from-c-to-rust-a-42-day-developer-challenge/
Chris Woodruff, экспериментающий .NET-разработчик, объявил старт своего 42-дневного пути погружения в Rust — язык системного программирования, совмещающий производительность, безопасность и отсутствие null:contentReference[oaicite:0]{index=0}.
🎯 Цели проекта
- Жить и дышать Rust — по одному уроку в день.
- Противостоять строгому borrow checker.
- Осознанно учиться и делиться выводами от лица C#-разработчика.
🛠 Что ожидается изучить
- Владение памятью, шаблоны, трейты, времена жизни (`lifetimes`).
- Яркие сравнения Rust и C#: синтаксис, ownership vs GC, ошибки компилятора:contentReference[oaicite:2]{index=2}.
- Краткие ежедневные отражения из .NET-мира.
📅 Примерный план на 42 дня
1. День 1–7: Почему Rust? Установка, cargo new vs dotnet new, "Hello, World!", переменные, функции:contentReference[oaicite:4]{index=4}.
2. День 8–14: Неделя владения — темы: ownership, borrowing, borrow checker:contentReference[oaicite:5]{index=5}.
3. День 15–42: Структуры, перечисления (`enum`), match, Option<T>, Result<T, E>, модули, ошибки, трейты, дженерики, лямбды и многое другое.
💬 Голос из сообщества
> «What happens when a C# dev swaps null for Option, garbage collection for ownership… You get 42 days of brain‑bending, compiler‑fighting…»
✨ Подытожим
- Проект идёт с апреля 2025 года, уже опубликованы десятки дневных эссе.
- Каждая запись по мотивам реального опыта: «why won’t this compile?!», сравнения с привычным C#.
- В финале — обзор полученного опыта, личные инсайты и примеры рабочего CLI‑приложения на Rust:contentReference[oaicite:8]{index=8}.
🚀 Готовы бросить вызов себе и глубже понять Rust?
Следите за дневником Woody и за входом в мир безопасных без‑GC систем прямо с .NET-опытов!
🔗 Подробнее: From C# to Rust: A 42-Day Developer Challenge
https://woodruff.dev/from-c-to-rust-a-42-day-developer-challenge/
Media is too big
VIEW IN TELEGRAM
Какой язык более читаемый: C# или Python? Программисты забивают на безопасность?
Обсуждаем эти и другие холиварные темы в шоу Контура «Согласен — не согласен», где сталкиваются два представителя разных IT-профессий, каждый со своим мнением и бэкграундом.
Cмотрите самые горячие выпуски🔥
➡️ С# vs Python-разработчики: какой язык круче
➡️ Джун vs cеньор-разработчики: нужны ли джуны в бигтехе
➡️ Бэкендер vs фронтендер: кто больше страдает
➡️ Программист vs учитель информатики: делать ли программирование обязательным в школе
➡️ Безопасник vs программист: кто должен думать об уязвимости продукта
Новые дискуссии выходят в канале @KonturTech каждые две недели. Будет эмоционально, но с уважением.
16+. Реклама. АО «ПФ «СКБ Контур», ОГРН 1026605606620. 620144, Екатеринбург, ул. Народной Воли, 19А. Erid: 2SDnjcTtt77
Обсуждаем эти и другие холиварные темы в шоу Контура «Согласен — не согласен», где сталкиваются два представителя разных IT-профессий, каждый со своим мнением и бэкграундом.
Cмотрите самые горячие выпуски
Новые дискуссии выходят в канале @KonturTech каждые две недели. Будет эмоционально, но с уважением.
16+. Реклама. АО «ПФ «СКБ Контур», ОГРН 1026605606620. 620144, Екатеринбург, ул. Народной Воли, 19А. Erid: 2SDnjcTtt77
Please open Telegram to view this post
VIEW IN TELEGRAM
SQL_cheatsheet.pdf
754.9 KB
⚡️ SQL-шпаргалка, которая выручит в интервью, проекте и проде
Полный мастер-гайд по SQL в одном PDF: практичные примеры, чёткие объяснения и никакой воды.
Что внутри:
• 💬 Создание баз, таблиц и изменение схем
• 💬 Запросы любого уровня сложности: JOIN, GROUP BY, HAVING, PARTITION
• 💬 Подзапросы, CTE, оконные функции: ROW_NUMBER, RANK, DENSE_RANK
• 💬 VIEW, временные таблицы и работа с дубликатами
• 💬 Даты, строки, преобразования и агрегации
• 💬 Очистка данных, разбиение по разделителям
• 💬 UNION, INTERSECT, EXCEPT — управление сложными выборками
Затрагиваются и продвинутые кейсы:
• Парсинг адресов
• Кастомная сортировка
• Использование ISNULL и COALESCE
🧠 Это не просто набор команд — это концентрат боевого SQL-опыта.
Подходит для:
➡️ Подготовки к SQL-интервью
➡️ BI и аналитики
➡️ Web-разработки с базами
➡️ Встраивания SQL в проекты на Python, Go, Java и других языках
Полный мастер-гайд по SQL в одном PDF: практичные примеры, чёткие объяснения и никакой воды.
Что внутри:
• 💬 Создание баз, таблиц и изменение схем
• 💬 Запросы любого уровня сложности: JOIN, GROUP BY, HAVING, PARTITION
• 💬 Подзапросы, CTE, оконные функции: ROW_NUMBER, RANK, DENSE_RANK
• 💬 VIEW, временные таблицы и работа с дубликатами
• 💬 Даты, строки, преобразования и агрегации
• 💬 Очистка данных, разбиение по разделителям
• 💬 UNION, INTERSECT, EXCEPT — управление сложными выборками
Затрагиваются и продвинутые кейсы:
• Парсинг адресов
• Кастомная сортировка
• Использование ISNULL и COALESCE
🧠 Это не просто набор команд — это концентрат боевого SQL-опыта.
Подходит для:
➡️ Подготовки к SQL-интервью
➡️ BI и аналитики
➡️ Web-разработки с базами
➡️ Встраивания SQL в проекты на Python, Go, Java и других языках
🧠 Задача для .NET разработчиков: «Загадочная утечка памяти в ASP.NET Core приложении»
🧩 Уровень: Senior .NET / Backend Engineer
🎯 Цель: Найти и устранить причину роста памяти без падений и исключений
📍 Ситуация:
У вас — высоконагруженное API на ASP.NET Core (.NET 8), работающее под Linux в контейнере.
Сервис обрабатывает тысячи запросов в минуту. Мониторинг показывает:
- Память растёт стабильно, но не освобождается
- GC работает, но не очищает выделенную память
-
- Приложение не падает, но хост начинает свапать и тормозить
- При перезапуске — память очищается, но через 2–3 часа снова заполняется
❗ В логах — тишина, ошибок нет. Библиотеки:
---
🧩 Твоя задача:
1. Почему .NET GC может не освобождать LOH, даже при работе GC?
2. Какие действия вызывают накопление в LOH?
3. Как можно отследить, какие объекты скапливаются в памяти?
4. Чем опасен повторный вызов
5. Как корректно использовать
💡 Подсказка:
- LOH начинается с объектов > 85,000 байт
- Часто виноваты: большие строки, сериализация, `ToString()`, 🧠 Задача для .N🧠 Задача🧠 Задача
- Задача для .NETможет хранить сильные ссылки бесконечно, если не задано время жизни
- Частое создание
🧩 Уровень: S— может удерживать сокеты в TIME_WAIT и загонять GC в ступор
🛠 Решение:
1. Запускаем профилировщик:
2. Смотрим типы с самым большим retained size:
→ В коде — сериализация в JSON огромных объектов без ограничения глубины
3. Находим участок с
4. Исправления:
- Добавить настройки сериализации:
- Ограничить
- Использовать
5. Альтернатива: перейти на
📌 Вывод:
Даже без явных ошибок .NET-приложение может стабильно "утекать" в LOH — через сериализацию, кэш или неправильную работу с потоками. Только анализ дампа памяти и правильная конфигурация GC и кешей помогут найти такие проблемы.
@csharp_1001_notes
🧩 Уровень: Senior .NET / Backend Engineer
🎯 Цель: Найти и устранить причину роста памяти без падений и исключений
📍 Ситуация:
У вас — высоконагруженное API на ASP.NET Core (.NET 8), работающее под Linux в контейнере.
Сервис обрабатывает тысячи запросов в минуту. Мониторинг показывает:
- Память растёт стабильно, но не освобождается
- GC работает, но не очищает выделенную память
-
dotnet-counters
показывает рост в LOH (Large Object Heap)- Приложение не падает, но хост начинает свапать и тормозить
- При перезапуске — память очищается, но через 2–3 часа снова заполняется
❗ В логах — тишина, ошибок нет. Библиотеки:
Newtonsoft.Json
, HttpClient
, MemoryCache
, EF Core
.---
🧩 Твоя задача:
1. Почему .NET GC может не освобождать LOH, даже при работе GC?
2. Какие действия вызывают накопление в LOH?
3. Как можно отследить, какие объекты скапливаются в памяти?
4. Чем опасен повторный вызов
HttpClient
или StringBuilder
без очистки? 5. Как корректно использовать
MemoryCache
, чтобы избежать утечек?💡 Подсказка:
- Часто виноваты: большие строки, сериализация, `ToString()`,
-
- Частое создание
🧩 Уровень: S
🛠 Решение:
1. Запускаем профилировщик:
dotnet-gcdump collect -p <PID>
dotnet-gcdump analyze dump.gcdump
2. Смотрим типы с самым большим retained size:
List<string>
, byte[]
, MemoryStream
→ В коде — сериализация в JSON огромных объектов без ограничения глубины
3. Находим участок с
JsonConvert.SerializeObject(hugeObject)
без MaxDepth
4. Исправления:
- Добавить настройки сериализации:
new JsonSerializerSettings { MaxDepth = 5, ReferenceLoopHandling = Ignore }
- Ограничить
MemoryCache
по размеру:
new MemoryCache(new MemoryCacheOptions { SizeLimit = 100_000_000 });
- Использовать
HttpClientFactory
вместо new HttpClient()
на каждый запрос5. Альтернатива: перейти на
System.Text.Json
с Utf8JsonWriter
— меньше аллокаций📌 Вывод:
Даже без явных ошибок .NET-приложение может стабильно "утекать" в LOH — через сериализацию, кэш или неправильную работу с потоками. Только анализ дампа памяти и правильная конфигурация GC и кешей помогут найти такие проблемы.
@csharp_1001_notes