Библиотека шарписта | C#, F#, .NET, ASP.NET
Все самое полезное для C#-разработчика в одном канале. Наши курсы: https://clc.to/y3LDtw По рекламе: @tproger_sales_bot Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Ko'proq ko'rsatish📈 Telegram kanali Библиотека шарписта | C#, F#, .NET, ASP.NET analitikasi
Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 21 629 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 5 973-o'rinni va Rossiya mintaqasida 30 111-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 21 629 obunachiga ega bo‘ldi.
05 Oktabr, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -56 ga, so‘nggi 24 soatda esa 3 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 15.56% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 7.66% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 3 367 marta ko‘riladi; birinchi sutkada odatda 1 657 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 17 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent .net, шарписта, навигация, await, string kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Все самое полезное для C#-разработчика в одном канале.
Наши курсы: https://clc.to/y3LDtw
По рекламе: @tproger_sales_bot
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 06 Oktabr, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
Ma'lumot yuklanmoqda...
| Sana | Obunachilarni jalb qilish | Esdaliklar | Kanallar | |
| 06 Oktabr | 0 | |||
| 05 Oktabr | +6 | |||
| 04 Oktabr | +1 | |||
| 03 Oktabr | 0 | |||
| 02 Oktabr | 0 | |||
| 01 Oktabr | +4 |
| 2 | 📝 Логирование со строковой интерполяцией
Логирование c интерполяцией строк один из самых распространённых источников лишних аллокаций в .NET-приложениях.
Особенность в том, что код выглядит абсолютно нормально и работает правильно — просто дорого.
⏬ Что происходит с интерполяцией:
logger.LogInformation($"User {userId} logged in at {time}");
⏬ Компилятор разворачивает это примерно в:
logger.LogInformation(string.Format("User {0} logged in at {1}", userId, time));
Строка формируется до вызова метода. Если уровень логирования Information отключён, строка всё равно создаётся, занимает память и тут же выбрасывается сборщиком мусора.
⏬ Структурное логирование решает проблему:
logger.LogInformation("User {UserId} logged in at {Time}", userId, time);
Здесь строка — это шаблон. Аргументы передаются отдельно. Логгер сначала проверяет, активен ли уровень, и только потом форматирует сообщение. Если уровень выключен — аллокации нет вообще.
Бонус: структурное логирование позволяет индексировать поля в системах вроде Seq, Elasticsearch, Datadog — вы сможете искать по UserId как по полю, а не парсить текст.
⏬ Начиная с .NET 6 есть ещё лучший вариант через compile-time source generators:
// Генерирует оптимальный код на этапе компиляции:
[LoggerMessage(Level = LogLevel.Information, Message = "User {UserId} logged in at {Time}")]
partial void LogUserLogin(int userId, DateTime time);
Никаких аллокаций, никакого боксинга, максимальная производительность — и всё это без изменения читаемости кода.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор | 2 720 |
| 3 | 👨💻 Не показывайте технические ошибки пользователям
Когда приложение падает с необработанным исключением, стандартное поведение многих фреймворков — вывести стек вызовов прямо в ответ. Пользователь видит внутренние пути файлов, названия классов, фрагменты кода. Для злоумышленника это готовая карта уязвимостей.
⏬ Что происходит на практике
Допустим, в ASP.NET приложении возникает необработанное исключение. Без явной настройки middleware фреймворк вернёт подробный ExceptionDetails с именем метода, строкой кода и трассировкой стека. Атакующий получает информацию о структуре проекта, версиях библиотек и логике работы приложения без каких-либо усилий.
⏬ Как это закрыть
Правильный подход это перехват всех необработанныъ исключений. Нужно логировать их внутри системы и возвращать пользователю только нейтральное сообщение.
В ASP.NET это делается через UseExceptionHandler:
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
var logger = context.RequestServices
.GetRequiredService<ILogger<Program>>();
logger.LogError(exceptionHandlerPathFeature?.Error,
"Unhandled exception");
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new
{
message = "Something went wrong. Please try again later."
});
});
});
⏬ Что здесь происходит
Middleware перехватывает исключение, передаёт его в ILogger — туда, где его увидит только команда разработки — и возвращает клиенту простой JSON с универсальным сообщением об ошибке. Никаких деталей реализации наружу не уходит.
ILogger пишет в вашу систему мониторинга — будь то Application Insights, Seq, Serilog или любой другой инструмент. Вы по-прежнему видите полный стек вызовов и можете разобраться в причине ошибки. Пользователь при этом получает понятное сообщение, а не технический мусор.
Это базовая практика защиты приложений. Она не требует сложной архитектуры, достаточно одного middleware, настроенного в точке входа приложения.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view | 2 797 |
| 4 | 📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#garbage_collector | 3 245 |
| 5 | 🔐 NuGet: Microsoft меняет сертификат подписи
С 23 сентября Microsoft использует новый сертификат для подписи NuGet-пакетов. Если у вас настроен allowlist доверенных сертификатов, сборки могут начать падать с NU3034.
Что сделать:
dotnet nuget trust author Microsoft \
9A1B131BEE0605433056A4EA3815478A8E177961A968C6C0027C1093D1FEB630 \
--algorithm SHA256
Старые сертификаты удалять не нужно — они нужны для уже опубликованных пакетов.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_news | 3 764 |
| 6 | 🤩 Как поймать зависший .NET-сервис
Приложение начинает тормозить, запросы зависают, а в логах — ничего полезного? Можно автоматически снять memory dump в момент проблемы и потом разобрать состояние процесса.
➡️ Идея простая:
var task = Task.Run(() => { });
if (!task.Wait(3000))
{
// ThreadPool, вероятно, перегружен
// → создаём memory dump
}
➡️ Dump позволяет посмотреть:
— какие потоки зависли;
— где стоят Task;
— что происходит в ThreadPool;
— какие объекты находятся в памяти.
На Windows для создания dump можно использовать MiniDumpWriteDump, а в Linux — встроенный в .NET createdump. А дальше .dmp открывается в Visual Studio — можно исследовать call stacks, переменные и состояние потоков.
💡 Особенно полезно для production-проблем, которые невозможно нормально воспроизвести локально.
🔗 Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view | 3 809 |
| 7 | ⚙️ yield return не бесплатный
Итераторы выглядят просто, но работают иначе:
IEnumerable<int> GetIds()
{
foreach (var item in _items)
yield return item.Id;
}
Читается как обычный цикл. Но компилятор превращает такой метод в конечный автомат со вспомогательными классами и состоянием. Именно поэтому итераторы такие выразительные — но и именно поэтому они не бесплатны.
❓ Где это становится проблемой
На большинстве путей yield return это правильный выбор. Код чище, API удобнее, читаемость выше.
Но на горячих путях, где метод вызывается тысячи раз в секунду, повторное создание объектов итератора и дополнительные слои абстракции начинают влиять на производительность. Не катастрофически, но измеримо.
❓ Что делать на критичных участках
Если профилировщик показал, что итератор узкое место, есть несколько альтернатив.
🟡 Заполнение буфера, переданного вызывающей стороной:
void FillIds(Span<int> buffer)
{
for (int i = 0; i < _items.Count; i++)
buffer[i] = _items[i].Id;
}
🟡 Возврат конкретной коллекции:
List<int> GetIds()
{
var result = new List<int>(_items.Count);
foreach (var item in _items)
result.Add(item.Id);
return result;
}
🟡 Прямой цикл внутри горячего кода без промежуточных перечислений:
for (int i = 0; i < _items.Count; i++)
Process(_items[i].Id);
yield return стоит использовать тогда, когда он делает API лучше и код понятнее. Но не стоит считать его нулевым по стоимости. Если участок горячий, то сначала замерьте, потом решайте.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор | 3 427 |
| 8 | 💡 Replace, Regex или StringBuilder?
Для замены текста в C# есть несколько инструментов. И выбирать их лучше не по принципу «что быстрее», а по задаче.
🔜 string.Replace() — когда ищем конкретный текст:
var result = text.Replace("cat", "dog");
🔜 Regex.Replace() — когда нужен шаблон:
var result = Regex.Replace(
text,
@"\d+",
"#");
Например, заменить все числа на #.
🔜 StringBuilder.Replace() — когда последовательно изменяем большой текст:
var sb = new StringBuilder(text);
sb.Replace("cat", "dog");
sb.Replace("foo", "bar");
var result = sb.ToString();
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view | 3 044 |
| 9 | ⚙️ Настоящие атомарные операции
Если Volatile решает проблему видимости, то Interlocked решает проблему атомарности. Операции реализованы на уровне процессора и выполняются как неделимые единицы — никакой другой поток не может вмешаться в середину
➡️ Самый частый сценарий это счётчик, который обновляют несколько потоков:
private int _counter;
public void Increment()
{
Interlocked.Increment(ref _counter);
}
Без Interlocked операция _counter++ на самом деле три шага: прочитать, прибавить, записать. Два потока могут выполнить их одновременно и затереть результат друг друга. Interlocked.Increment делает всё это за один неделимый шаг.
➡️ Lock-free генератор ID
Interlocked подходит для генерации уникальных идентификаторов без блокировок:
public int GetNextId()
{
return Interlocked.Increment(ref _id);
}
Каждый вызов гарантированно вернёт уникальное значение, даже если тысячи потоков вызывают метод одновременно.
➡️ CompareExchange: условное обновление
Самая мощная операция в арсенале Interlocked:
if (Interlocked.CompareExchange(ref _state, 1, 0) == 0)
{
// Успешно перешли из состояния 0 в 1
}
Логика простая: если текущее значение равно 0, заменить на 1 и вернуть старое значение. Если кто-то уже изменил _state, операция ничего не сделает. Это паттерн, на котором строятся lock-free кэши, планировщики и конкурентные очереди.
➡️ Volatile и Interlocked — не одно и то же
Их можно перепутать, но они решают разные задачи.
Volatile гарантирует, что поток видит актуальное значение переменной. Interlocked гарантирует, что сама операция выполняется безопасно, без вмешательства других потоков.
В реальных системах нередко нужны оба. Volatile чтобы читать свежие данные, Interlocked чтобы безопасно их менять.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view | 3 213 |
| 10 | 💪 Разминка перед трудовыми буднями
Что произойдёт?
❤️ — список станет [1, 3]
🔥 — InvalidOperationException
👍 — цикл пропустит 2
Ответ спрячем здесь:
🔥 InvalidOperationException
foreach использует List<T>.Enumerator. После Remove() коллекция изменяется, перечислитель обнаруживает изменение при следующем MoveNext() и выбрасывает исключение.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#dotnet_challenge | 3 232 |
| 11 | 🧩 Middleware в ASP.NET Core: 3 ловушки
Middleware — звено HTTP pipeline:
app.Use(async (context, next) =>
{
Console.WriteLine("Request");
await next(context);
Console.WriteLine("Response");
});
1️⃣ Забыл next() — остановил pipeline
await _next(context);
Если его не вызвать, middleware ниже и endpoint не выполнятся.
2️⃣ Scoped-сервис не стоит инжектить в конструктор
Middleware переиспользуется между запросами, поэтому Scoped лучше получать в InvokeAsync:
public async Task InvokeAsync(
HttpContext context,
IMyScopedService service)
{
await _next(context);
}
3️⃣ После начала ответа менять его уже нельзя
context.Response.StatusCode = 503; // 💥
Если response уже отправляется, будет InvalidOperationException.
💡 Для действий до отправки используйте Response.OnStarting().
И ещё: не передавайте scoped-сервис в Task.Run после завершения запроса — его scope уже мог быть уничтожен. Для фоновой работы создавайте новый scope или используйте BackgroundService 🧠
🔗 Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминатор | 3 318 |
| 12 | 📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#garbage_collector | 3 335 |
| 13 | 🦆 Duck typing в C# — почти как в TypeScript
В TypeScript достаточно, чтобы у объекта был нужный метод:
function foo(a: { Do(): void }) {
a.Do();
}
🔜 В C# так напрямую нельзя:
class A
{
public void Do() => Console.WriteLine("A.Do");
}
class B
{
public void Do() => Console.WriteLine("B.Do");
}
🔜 У A и B нет общего интерфейса. Но хочется вызвать:
Foo(new A());
Foo(new B());
И здесь на сцену выходят interceptors — экспериментальная возможность компилятора C#.
🌞 Идея:
[DuckShape]
public interface IDoable
{
void Do();
}
public static partial class Ops
{
[DuckTyped]
public static void Foo(IDoable value)
=> value.Do();
}
📍 Source generator создаёт адаптер:
internal readonly struct ShapeAdapter_IDoable_A : IDoable
{
private readonly A _value;
public ShapeAdapter_IDoable_A(A value)
=> _value = value;
public void Do() => _value.Do();
}
А interceptor подменяет вызов и оборачивает A или B в подходящий адаптер.
🔴 В итоге:
Ops.Foo(new A()); // A.Do
Ops.Foo(new B()); // B.Do
Работает и с properties — например, можно описать INameable с Name { get; set; }, а затем передать обычный Person, не меняя его код.
⚠️ Но это скорее интересный PoC, чем готовая замена интерфейсам:
— interceptors остаются экспериментальной возможностью;
— нужен source generator;
— есть ограничения и не покрытые edge cases;
— появляется дополнительная магия на этапе компиляции.
🔗 Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_view | 3 626 |
| 14 | 🧠 Почему .NET-под съедает всю память?
kubectl top pod показывает 1 ГБ, а managed heap занимает всего 300 МБ. Куда делись остальные 700?
Память .NET-процесса — это не только GC:
— managed heap;
— JIT и загруженные сборки;
— стеки потоков;
— native-библиотеки;
— буферы сокетов;
— runtime и TLS.
Поэтому одного GCHeapHardLimitPercent недостаточно: он ограничивает только managed heap.
🔴 Что проверить:
kubectl top pod
dotnet-counters monitor -p <pid> System.Runtime
dotnet-gcdump collect -p <pid>
dotnet-dump collect -p <pid>
🔴 И ещё несколько практических моментов:
→ не выставляй всем подам одинаковые memory limits;
→ проверь AsNoTracking() и проекции в EF Core;
→ ищи .Result, .Wait() и блокирующий I/O;
→ тестируй GC под реальным memory limit контейнера.
🔗 Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминатор | 3 640 |
| 15 | 🧑💻 Забытый await: от race condition до DoS-атаки
В C# ключевое слово async — это инструкция компилятору превратить метод в state machine. await отмечает точку логической приостановки. Всё просто: выполнение не должно продолжаться, пока результат не существует.
При await весь код выполняется синхронно, пока не достигнет I/O или функции, возвращающей Task. Если Task не завершён, происходит раскрутка кадра стека, и поскольку обрамляющие методы приостановлены до самого верха, поток может быть освобождён в пул потоков.
Позже задача завершается, продолжение планируется и выполнение возобновляется там, где остановилось. Это не параллельное выполнение, это приостановка и возобновление.
Если забыли await:
var task = GetDataAsync();
// забыли await
Use(task);
Это режим «запустил и забыл» (fire-and-forget). Последствия:
• выполнение продолжается немедленно
• зависимость не обеспечивается
• исключения выходят за пределы логического стека вызовов
Что может произойти с приложением
⚠️ Забытый await может привести к классическому состоянию гонки: код продолжает выполнение до завершения критической операции, например, проверки прав доступа, открывая окно для эксплуатации.
Атакующий может успеть получить доступ к данным между моментом начала проверки и её завершением.
⚠️ Когда исключения выходят за пределы логического стека вызовов, они могут быть проглочены без логирования. Это маскирует неудачные попытки аутентификации, SQL-инъекции или другие атаки.
⚠️ Истощение пула потоков как вектор DoS-атаки. При высокой нагрузке неправильное использование async/await приводит к истощению пула потоков. Злоумышленник может намеренно генерировать запросы, эксплуатирующие блокирующие операции.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминатор | 3 689 |
| 16 | 😭 Как не потратить недельный лимит AI-кодинга за три дня?
Разберём на вебинаре, как тратить меньше на AI-агентов — без потери качества кода.
🔘 Поговорим о том:
— когда дорогая модель действительно нужна, а когда хватит дешёвой;
— сколько стоит один прогон и куда уходят токены;
— какие задачи можно отдавать субагентам;
— как настроить маршрутизацию моделей;
— что проверять в AI-коде перед merge.
✏️ Покажем всё на конкретных цифрах и вживую: сравним расходы до и после.
⬇️ 18 сентября, 19:00 МСК
⬇️ 1,5 часа · бесплатно
⬇️ Арсений Харланов и Олег Лайок
💬 Пишите в комментариях, где упираетесь в лимиты и на что уходят деньги. Самые залайканные вопросы разберём на вебинаре.
🔗 Зарегистрироваться на вебинар | 3 592 |
| 17 | 🧩 Union types появились в ASP.NET Core на .NET 11
В C# 15 можно описать тип с несколькими допустимыми вариантами:
public union IntOrString(int, string);
Такой endpoint может вернуть либо число, либо строку:
app.MapGet("/max-unavailable", () => new IntOrString(2));
JSON останется обычным:
2
или:
"25%"
Без $type и дополнительных обёрток.
Главный плюс — компилятор проверяет, что switch обработал все варианты union.
Поддерживается в Minimal APIs, MVC, SignalR, Blazor и OpenAPI.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#async_news | 3 828 |
| 18 | 🔍Тестовое собеседование с Senior C# разработчиком уже завтра
15 сентября (уже завтра!) в 19:00 по МСК приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle C# разработчика.
Как это будет:
📂 Александр Моргунов, старший C# разработчик с опытом 7+ лет в Европейских высоконагруженных сервисах, будет задавать реальные вопросы и задачи разработчику-добровольцу;
📂 Александр будет комментировать каждый ответ респондента, чтобы дать понять, чего от вас ожидает собеседующий на интервью;
📂 В конце можно будет задать любой вопрос Александру.
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для C# разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_csharp_bot
Реклама.
О рекламодателе. | 2 207 |
| 19 | С днем программиста, коллеги!
Желаем, чтобы код компилировался с первого раза, баги находились до релиза, а таски «на пять минут» действительно занимали пять минут.
И конечно, пусть в жизни будет больше приятных сюрпризов — один из них мы уже подготовили. Скорее переходите по ссылке, трясите коробку и забирайте свой подарок ко Дню программиста: https://tprg.ru/YtJ2 | 3 925 |
| 20 | 🧠 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 | 3 691 |
