C# (C Sharp) programming
18.7K subscribers
860 photos
44 videos
8 files
728 links
По всем вопросам- @haarrp

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

@ai_machinelearning_big_data - Machine learning

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

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

@pythonlbooks- книги📚

Реестр РКН: https://clck.ru/3Fk3kb
Download Telegram
Не все стратегии балансировки нагрузки одинаково полезны.

Если ты используешь 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

А какая стратегия у тебя по умолчанию?
🎯 Открытый урок «Сетевой чат на C#».

🗓 22 января в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «C# Developer».

На вебинаре:
✔️ Рассмотрим написание сетевого приложения на C#.
✔️ Мы реализуем простые клиент и сервер с помощью одного из сетевых протоколов.
✔️Также затронем темы многопточности и асинхронности

Кому будет полезно:
• Вебинар будет полезен начинающим разработчикам, желающим разобраться в сетевом и многопочном\асинхронном программировании.

Что вы получите:
• По итогам вебинара смогут проектировать сетевые приложения.
• Получат представление о работе сетевых протоколов, и многопоточности\асинхронности в приложениях.
• На практике попробуют разработать такое приложение.

🔗 Ссылка на регистрацию: https://otus.pw/zifo/?erid=2W5zFJaPXHA

Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.
⚡️ В .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 => ServiceDescriptor.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
36%
0 2 0 2
11%
0 2 4 4
10%
4 4 4 4
33%
4 4 0 2
9%
🥒
This media is not supported in your browser
VIEW IN TELEGRAM
🖥 Многопоточность в .NET часто сводят к lock. Но в реальных системах этого недостаточно — особенно под нагрузкой, в легаси-коде и распределённых сценариях.

📕 На открытом уроке разберём, какие инструменты действительно есть в .NET и как выбирать подходящий примитив под конкретную задачу. Рассмотрим Monitor, Mutex, Semaphore, а также другие примитивы из System.Threading: ReaderWriterLockSlim, Barrier, ManualResetEventSlim, SpinLock.

❗️ Вы увидите практические примеры, типовые ошибки и узнаете, где блокировки становятся узким местом. Урок будет полезен разработчикам, работающим с высоконагруженными системами и легаси-кодом, а также тимлидам, которые проектируют архитектуру и отвечают за производительность.

📣 Встречаемся 27 января в 20:00 МСК в преддверии старта курса «C# Developer. Professional». Регистрация открыта: https://otus.pw/t6Xj/
📦 Всё ещё не используешь 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