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

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

@ai_machinelearning_big_data - Machine learning

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

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

@pythonlbooks- книги📚

Реестр РКН: https://clck.ru/3Fk3kb
Download Telegram
⚡️ В .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
37%
0 2 0 2
10%
0 2 4 4
10%
4 4 4 4
32%
4 4 0 2
10%
🥒
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
This media is not supported in your browser
VIEW IN TELEGRAM
⚙️ Вы настраиваете ASP.NET Core «по наитию» и тратите время на поиск, почему приложение ведет себя по-разному в продакшене и локально?

📆 29 января в 20:00 OTUS проводит открытый урок «Конфигурирование приложения ASP.NET Core» в преддверии старта курса «C# ASP.NET Core разработчик».

На занятии разберем, как выстроить прозрачную и управляемую систему настроек: appsettings.json, провайдеры конфигурации, приоритет применения конфигураций, настройки специфичные для среды и шаблон Options для работы с настройками. Вы поймете, как проектировать конфигурации так, чтобы приложения были стабильными и предсказуемыми.

❗️Урок будет полезен разработчикам ASP.NET Core начального и среднего уровня, которые хотят систематизировать знания и работать по индустриальным стандартам.

➡️ Регистрируйтесь на бесплатный урок: https://tglink.io/f0de1b0a6e87?erid=2W5zFH3PFGL

🎁 Все участники открытого урока получат скидку на обучение.
#реклама
О рекламодателе
Перестань падать из-за одного внешнего 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