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

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

@ai_machinelearning_big_data - Machine learning

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

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

@pythonlbooks- книги📚

Реестр РКН: https://clck.ru/3Fk3kb
Download Telegram
⚡️ В мире #dotnet есть куда больше вариантов для messaging, чем RabbitMQ и Kafka.

И для real-time систем эти инструменты часто избыточны.

Большинство брокеров сообщений заточены под надёжность, сложную маршрутизацию и enterprise-сценарии.
Это отлично, когда нужны гарантии доставки и сложные пайплайны.
Но если система живёт на частых событиях, минимальной задержке и мгновенной реакции, этот вес начинает мешать.

Здесь идеально заходит NATS.

NATS - лёгкая и сверхбыстрая система обмена сообщениями, спроектированная именно для real-time:
- минимальная латентность
- простая модель
- высокая масштабируемость

Отлично подходит для:
- телеметрии и sensor data
- live-обновлений
- edge-систем
- сценариев, где важно «сейчас», а не «через секунду»

В статье подробно разобрано:
- когда NATS имеет смысл (а когда нет)
- сравнение с RabbitMQ и Kafka
- использование NATS в .NET с понятными примерами кода
- Pub/Sub, queue groups и request–reply

https://thecodeman.net/posts/introduction-to-nats-real-time-messaging
Интеграционные тесты прямо в CI/CD - максимум уверенности в коде 🚀

Я запускаю интеграционные тесты прямо внутри CI/CD пайплайна.
Так я проверяю не абстракции и моки, а реальное поведение системы.

Всё это возможно благодаря:
- Docker
- Testcontainers

Идея простая:
ты поднимаешь реальные внешние сервисы как контейнеры и используешь их прямо в тестах.

В примере поднимаются:
- PostgreSQL
- Redis
- Keycloak

Контейнеры:
- автоматически стартуют перед тестами
- доступны из кода приложения
- уничтожаются после выполнения тестов

Почему это работает лучше моков:
- тесты максимально близки к продакшену
- одинаковое поведение локально и в CI
- сразу ловятся проблемы с конфигурацией, миграциями, auth
- меньше сюрпризов после деплоя

Особенно полезно для:
- backend-сервисов
- микросервисной архитектуры
- систем с авторизацией и внешними зависимостями
- .NET-приложений с серьёзной бизнес-логикой

Если хочешь вывести интеграционное тестирование в .NET на новый уровень — Testcontainers стоит попробовать обязательно.

#dotnet, #testing
🔍 Как делать code review, которые находят реальные баги, а не только придираются к стилю

Большинство code review застревают на форматировании, нейминге и мелочах. В итоге реальные проблемы - логические ошибки, гонки, неправильные инварианты - проходят мимо.

Идея правильного code review:
— Проверять поведение кода, а не его внешний вид
— Искать сценарии отказа, а не соответствие линтеру
— Думать как система, а не как форматтер

Что реально стоит смотреть на ревью:
• Граничные случаи и ошибки в бизнес-логике
• Null / empty сценарии и некорректные состояния
• Побочные эффекты и порядок операций
• Работа с асинхронностью, транзакциями и ресурсами
• Соответствие инвариантам доменной модели

Инструменты с AI-ассистентами для code review помогают сместить фокус:
— меньше шума про стиль
— больше внимания к логике и потенциальным багам
— автоматические подсказки прямо в PR

Хороший code review — это не «код красивый»,
а «код не сломается в проде».
В какой строке возникнет первое исключение?

#ПятничныйКвиз
В какой строке возникнет первое исключение?
Anonymous Quiz
25%
1
11%
2
8%
3
7%
4
5%
5
29%
Весь код выполнится корректно
14%
🎄
💡 В EF Core есть штука, о которой многие забывают: CompileAsyncQuery.

С её помощью можно заранее скомпилировать LINQ-запрос,а потом выполнять его асинхронно: быстрее и без лишнего overhead’а.

И важный еще момент:
вам не нужно писать отдельную “async-версию” самого LINQ-запроса.
EF сам оборачивает выполнение в асинхронный пайплайн. Немного странно, но работает.

Пример:

private static Func<AppDbContext, string, Task<Newsletter?>> GetByTitle =
EF.CompileAsyncQuery(
(AppDbContext context, string title) =>
context.Set<Newsletter>()
.FirstOrDefault(c => c.Title == title)
);

public async Task<Newsletter?> GetNewsletterByTitleAsync(string title)
{
return await GetByTitle(this, title);
}


Что получаем:

• повторные запросы выполняются быстрее
• нет лишней компиляции выражений
• async-подход сохраняется

Если в проекте есть часто вызываемые запросы - Compiled Queries могут дать хороший прирост производительности, особенно под нагрузкой.
✔️ C# стал языком 2025 года по версии TIOBE.

Индекс TIOBE подвел итоги года: звание «Язык 2025 года» досталось C#, который показал рекордный рост популярности (+2.94%)? однако в общем зачете он по-прежнему занимает 5-ю строчку. Абсолютным лидером остается Python с 22.61% долей рынка.

В первой пятерке произошли перестановки: язык C поднялся на 2 место, сместив C++ на 4-ю позицию; 3 место досталось Java, а R вернулся в топ-10. Провал года - Go, который неожиданно сдал позиции, опустившись сразу на 16-е место.

Индекс оценивает популярность технологий на основе поисковых запросов, активности комьюнити и количества обучающих материалов.

https://www.tiobe.com/tiobe-index/
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 Как просто добавить multi-tenant в .NET через заголовок запроса

Иногда нужно понимать, какому клиенту (tenant) принадлежит запрос.

Самый простой вариант - передавать X-TenantId в HTTP-заголовке и читать его в сервисе.

Пример сервиса:


public sealed class TenantProvider
{
private const string TenantIdHeaderName = "X-TenantId";
private readonly IHttpContextAccessor _httpContextAccessor;

public TenantProvider(IHttpContextAccessor httpContextAccessor)
=> _httpContextAccessor = httpContextAccessor;

public string TenantId =>
_httpContextAccessor.HttpContext.Request.Headers[TenantIdHeaderName];
}
⚡️ Какие строки выведутся и в каком порядке(override + overload + dynamic)


using System;

class Base
{
public virtual void Foo(object o) => Console.WriteLine("Base.Foo(object)");
}

class Derived : Base
{
public override void Foo(object o) => Console.WriteLine("Derived.Foo(object)");
public void Foo(string s) => Console.WriteLine("Derived.Foo(string)");
}

class Program
{
static void Main()
{
Base b = new Derived();

b.Foo("A");

((Derived)b).Foo("A");

dynamic d = b;
d.Foo("A");

object x = "A";
d.Foo(x);

d.Foo(null);
}
}


📌 Ответ:

Derived.Foo(object)
Derived.Foo(string)
Derived.Foo(string)
Derived.Foo(string)
Derived.Foo(string)


Пояснение:

1) b.Foo("A")
Статический тип переменной - Base.
Компилятор видит только Foo(object).
Вызов виртуальный, поэтому выполняется override:
Derived.Foo(object)

2) ((Derived)b).Foo("A")
Статический тип - Derived.
Есть перегрузка Foo(string), она точнее для string:
Derived.Foo(string)

3) dynamic d = b; d.Foo("A")
dynamic откладывает выбор метода до runtime.
Реальный тип объекта - Derived.
Реальный тип аргумента - string:
Derived.Foo(string)

4) object x = "A"; d.Foo(x)
Для dynamic учитывается реальный тип аргумента.
x содержит string:
Derived.Foo(string)

5) d.Foo(null)
null подходит и для object, и для string.
string - более специфичный тип:
Derived.Foo(string)
Please open Telegram to view this post
VIEW IN TELEGRAM
.NET 9 стал гораздо устойчивее к сбоям 💪

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

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

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

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

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

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