C# (C Sharp) programming – Telegram
C# (C Sharp) programming
18.7K subscribers
883 photos
47 videos
8 files
737 links
По всем вопросам- @haarrp

C# - обучающий канал Senior C# разработчика.

@ai_machinelearning_big_data - Machine learning

@itchannels_telegram - 🔥лучшие ит-каналы

@csharp_ci - C# академия

@pythonlbooks- книги📚

Реестр РКН: https://clck.ru/3Fk3kb
Download Telegram
.NET 9 стал гораздо устойчивее к сбоям 💪

В .NET 9 появились официальные пакеты для отказоустойчивости:

- Microsoft.Extensions.Resilience
- Microsoft.Extensions.Http.Resilience

Они построены поверх Polly, поэтому API знакомый - легко описывать политики:

- retry
- circuit-breaker
- fallback
- timeout
- hedging
- rate limiter

Подключаете и ваши HTTP-клиенты и сервисы автоматически восстанавливаются при сетевых ошибках и таймаутах.

Итог: меньше падений и больше стабильности. Отлично для продакшена 🚀
Обещанного 3 года ...
Не все стратегии балансировки нагрузки одинаково полезны.

Если ты используешь YARP (Yet Another Reverse Proxy) в .NET - у него есть 5 встроенных способов распределять трафик между серверами. Но какой выбрать?

Вот понятный разбор:

1) RoundRobin (по кругу)
Классика: запросы равномерно идут по очереди на каждый сервер.
просто
плохо работает, если сервера/запросы не одинаковые по скорости

2) LeastRequests (минимум активных запросов)
Самый “умный” вариант: отправляет запрос туда, где сейчас меньше всего работы.
отлично при разном времени обработки запросов
помогает снизить задержки на “хвосте” (tail latency)

3) Random (случайно)
Сервер выбирается случайно.
неожиданно хорошо работает при большом потоке однотипных запросов
может иногда “не повезти” и нагрузить один сервер сильнее

4) PowerOfTwoChoices (2 случайных - выбираем лучший)
Баланс между качеством и стоимостью: берём 2 случайных сервера и выбираем тот, где меньше активных запросов.
почти как LeastRequests, но дешевле по логике
не надо проверять все сервера каждый раз

5) FirstAlphabetical (первый доступный)
Всегда выбирает “первый” сервер из списка (условно самый верхний/раньше по имени).
хорошо для failover (есть основной сервер, остальные - запасные)
плохо распределяет нагрузку (по сути почти без балансировки)

Большинство по привычке ставят RoundRobin, но если время обработки запросов разное - переход на LeastRequests часто заметно улучшает tail latency.

Разбор с примерами, как масштабировать ASP.NET Core API через YARP

А какая стратегия у тебя по умолчанию?
⚡️ В .NET кэш - это всегда выбор: максимальная скорость или единые данные между серверами.

IMemoryCache
Очень быстрый
Работает только внутри одной ноды
(в кластере из 10 серверов у вас 10 разных кэшей)

Redis / IDistributedCache
Один общий кэш на все ноды - данные одинаковые
Медленнее: сеть + сериализация + лишние накладные расходы

Правильный подход - Hybrid Cache.

Он не заставляет выбирать - он комбинирует оба мира:

- L1 (Local / RAM) - сначала читаем из памяти приложения (самый быстрый слой)
- L2 (Distributed / Redis) - если локально нет, идём в общий кэш
- Source (DB/API) - если нет и там, берём из источника и прогреваем оба уровня

🚀 скорость как у MemoryCache
🔒 данные согласованы между нодами как в Redis
📉 меньше нагрузки на БД и меньше «холодных» запросов

Microsoft делает нативный HybridCache, но если нужно решение уже сейчас - FusionCache остаётся самым надёжным и реально продакшн-готовым вариантом.

📌 Гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
🚀 Опасен баг, который вылазит через 3 дня после релиза.

И это ровно тот риск, который прячется в стандартном Options Pattern в .NET.

Ты спокойно делаешь так:
- биндишь appsettings.json в класс
- инжектишь настройки через DI
- приложение стартует без проблем

А потом внезапно

В прод падает , потому что:
не задан обязательный ApiKey
RetryCount = 0
строка подключения пустая

И ты узнаёшь об этом только тогда, когда кто-то нажмёт нужную кнопку в твоем приложении.

Вот почему принцип Fail Fast критичен для конфигов:
если конфигурация невалидна - приложение не должно запускаться вообще.

Как это сделать правильно:
используй расширение Options Pattern через IValidateOptions.

Суть подхода:
1) задаём правила (например: ApiKey не null, `RetryCount > 0`)
2) регистрируем валидатор
3) если условия нарушены - DI кидает исключение сразу при старте

Можно прйти дальше и подключиит FluentValidation, чтобы условия были:
- чище
- читабельнее
- удобнее расширять

Полная реализация: https://milanjovanovic.tech/blog/options-pattern-validation-in-aspnetcore-with-fluentvalidation?utm_source=X&utm_medium=social&utm_campaign=05.01.2026
⚡️ Автоматическая регистрация Minimal APIs в .NET - без ручного маппинга

Если в проекте 20+ endpoint’ов, app.MapGet/MapPost превращается в ад.
Решение - авторегистрировать endpoints через DI.

Идея:
1) Делаешь общий интерфейс IEndpoint
2) Каждый endpoint реализует его
3) На старте приложения сканируешь сборку, регистрируешь все реализации в DI
4) Достаёшь их из DI и вызываешь MapEndpoints()

Плюсы:
чистый Program.cs
каждый endpoint в отдельном файле
масштабируется без хаоса
легко тестировать и поддерживать

Пример паттерна:


builder.Services.AddEndpoints(typeof(Program).Assembly);

public interface IEndpoint
{
void Map(IEndpointRouteBuilder app);
}

public static class EndpointExtensions
{
public static IServiceCollection AddEndpoints(this IServiceCollection services, Assembly assembly)
{
var endpoints = assembly.DefinedTypes
.Where(t => !t.IsAbstract && !t.IsInterface && typeof(IEndpoint).IsAssignableFrom(t))
.Select(t => ServiceDenoscriptor.Transient(typeof(IEndpoint), t))
.ToArray();

services.TryAddEnumerable(endpoints);
return services;
}

public static void MapEndpoints(this WebApplication app)
{
foreach (var endpoint in app.Services.GetServices<IEndpoint>())
endpoint.Map(app);
}
}
Что выведет на экран этот код?
Anonymous Quiz
38%
0 2 0 2
11%
0 2 4 4
10%
4 4 4 4
31%
4 4 0 2
9%
🥒
📦 Всё ещё не используешь Central Package Management в .NET?

Открой свой .csproj прямо сейчас.

Пакеты обычно выглядят так:
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="WolverineFx" Version="5.6.0" />

И в итоге проект превращается в мусорку из версий.

А теперь представь, что это будет так:
<PackageReference Include="Serilog" />
<PackageReference Include="WolverineFx" />

Вот в этом и кайф Central Package Management.

Что он даёт:
.csproj становится чистым и читаемым
никто случайно не поставит “левую” версию пакета
вся команда работает на одинаковых версиях библиотек
сборка становится предсказуемой и детерминированной

Как работает:
Ты управляешь версиями централизованно через файл
Directory.Packages.props в корне репозитория.

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

Если у тебя монорепа или несколько проектов - это must-have.
🖥 Как обычные Linux-пользователи смотрят файлы:


$ ls -a


А как смотрю я:


$ echo */ *. *


Этот трюк выводит всё “простым” способом через glob-расширение:


- */ покажет папки
- * покажет обычные файлы
- .* покажет скрытые файлы


Плюс это удобно тем, что результат можно сразу передавать дальше в команды, не парся вывод ls.
Please open Telegram to view this post
VIEW IN TELEGRAM
Перестань падать из-за одного внешнего API - добавь Fallback в .NET через Resilience Pipeline 🛡️

Вместо того чтобы приложение валилось, когда GitHub (или любой сервис) не отвечает, ты можешь вернуть безопасный дефолт и продолжить работу.

Идея простая:
Ты добавляешь fallback-стратегию в pipeline, и если запрос падает — система вернёт запасной результат.

Что происходит в примере:

— В DI регистрируется Resilience Pipeline
— Добавляется FallbackStrategy
— Если вызов неудачный, возвращается GitHubUser.Empty вместо исключения

Дальше в endpoint ты не вызываешь HttpClient напрямую — ты запускаешь его через pipeline:

pipeline.ExecuteAsync(...)

И если API:
упало
вернуло ошибку
словило таймаут

Пользователь не увидит 500. Он получит контролируемый ответ.

Это особенно важно для:
- внешних API
- микросервисов
- нестабильных сетей
- интеграций с SaaS

Fallback — это не про «скрыть ошибку».
Это про graceful degradation, когда система продолжает жить даже при частичных сбоях.

Надёжность — это архитектура, а не try/catch в каждом методе.
#dotnet #backend #architecture
🏗️ Пытаться вытаскивать микросервисы из “спагетти-монолита” - почти всегда плохая идея.

Вместо красивой архитектуры ты получишь распределённую кашу, ещё больше зависимостей, ошибок и боли при поддержке.

Самый безопасный путь миграции - паттерн Strangler Fig:
выносить функциональность по кускам, постепенно “замещая” монолит.

Но есть важное условие:
сначала нужно привести систему к Modular Monolith.

То есть:
- чётко выделить границы модулей
- изолировать данные
- оставить только чистые публичные API для общения между модулями

И только после этого выбирать, какой модуль выносить первым.

Как выбрать правильного кандидата на первый микросервис?
Ищи 4 “зелёных флага”:

1) Low Coupling - минимум зависимостей от других модулей
2) High Cohesion - логика внутри модуля максимально связная и цельная
3) Distinct Domain - чёткая бизнес-область (например, “платежи” или “инвойсинг”)
4) Scale Needs - модулю нужны другие ресурсы/масштабирование, чем остальной системе

Если модуль соответствует этим критериям - его можно вынести относительно безопасно,
не превращая архитектуру в распределённый хаос.
⚡️ 10 причин перейти на .NET 10 (чтобы это одобрил руководитель)

.NET 10 и C# 14 вышли 11 ноября 2025. Ниже - 10 причин, почему апгрейд реально стоит запланировать.

1) LTS-релиз
- .NET 10 - Long-Term Support, поддержка до 14 ноября 2028
- поддержка .NET 8 заканчивается 10 ноября 2026 → лучше не тянуть

2) Быстрее ASP.NET Core
- до +15% RPS по сравнению с .NET 8
- до -93% потребления памяти → меньше нагрузка и дешевле инфраструктура

3) Общий прирост производительности .NET
- сотни улучшений “из коробки” просто после апгрейда проекта

4) File-Based Apps (один .cs файл)
- можно сделать один файл *.cs и запускать напрямую
- удобно для CLI, автоматизации и утилит без создания проекта

5) Server-Sent Events (SSE)
- лёгкий способ стримить данные на клиента
- идеален для real-time обновлений без сложности WebSocket

6) Extension Members в C# 14
- более удобный синтаксис расширений
- можно расширять свойства и static members

7) Minimal APIs: Validation + JSON Patch
- встроенная валидация для Minimal APIs
- JSON Patch доступен из коробки

8) EF 10: LeftJoin / RightJoin в LINQ
- наконец-то нормальные LeftJoin/RightJoin
- запросы становятся проще и читаемее

9) EF 10: Named Query Filters
- можно заводить несколько фильтров на одну сущность
- включать/выключать их независимо

10) Улучшения Blazor
- Hot Reload для Blazor WASM и .NET on WASM
- профилирование производительности + диагностические счётчики

Источник/подробности:
antondevtips.com/draft/10-reasons-to-upgrade-to-dotnet-10/
⚡️ Модульный монолит хорош ровно настолько, насколько хороши его границы.

Если Module A может “по-тихому” лезть в базу Module B - у тебя не модули.
У тебя хаос, просто внутри одного репозитория.

Самое сложное в модульной архитектуре - не “разбить на папки”, а решить, что модуль вообще имеет право показывать наружу.

Моё правило для Public API:

1) Начинай с нуля
Считай, что любой класс должен быть приватным по умолчанию.

2) Открывай только по необходимости
Доступ даётся не “на будущее”, а только если другой модуль реально просит функциональность.

3) Экспортируй возможности, а не данные
API должно отражать сценарии (use-cases), а не “вот тебе таблица/репозиторий/DTO”.

И главное - просто договориться недостаточно.
Границы нужно технически запрещать нарушать: модификаторы, сборки, internal, анализаторы, тесты на зависимости.
Please open Telegram to view this post
VIEW IN TELEGRAM
Если вы не используете OpenTelemetry, вы буквально летите вслепую в продакшене.

И хорошая новость — вам не нужно переписывать код, чтобы получить “рентген-зрение” для своих сервисов.
Достаточно подключить правильные пакеты авто-инструментирования.

Вот базовый стартовый набор для .NET:

- AspNetCore — автоматически трейсит все входящие HTTP-запросы
- HttpClient — показывает тайминги и статусы всех исходящих API-вызовов
- EF Core — логирует реальные SQL-запросы и их длительность
- Npgsql — добавляет глубокий трейсинг для PostgreSQL
- StackExchange.Redis — помогает увидеть cache hits, misses и скачки латентности

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

Это уже не “логи и надежда”.
Это наблюдаемость продакшен-уровня.

Я разобрал, как всё это подключить к Grafana или Jaeger и получить полноценную визуализацию трейсов.

Полный гайд по настройке:
https://milanjovanovic.tech/blog/introduction-to-distributed-tracing-with-opentelemetry-in-dotnet?utm_source=X&utm_medium=social&utm_campaign=19.01.2026