C# Portal | Программирование
13.9K subscribers
1.15K photos
126 videos
29 files
928 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Сотрудничество, реклама: @devmangx

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
𝟭𝟱 инструментов и библиотек .NET, которые использует сообщество

Я задал в r/dotnet один вопрос: какие библиотеки .NET вы реально используете, о которых никто не говорит?

Тред собрал сотни ответов. Я отфильтровал те, у которых 10+ апвоутов.

CSharpier набрал 62 голоса. Refit — на втором месте. Дальше — набор инструментов с 30–31 голосами, о большинстве из которых разработчики либо не знают, либо почти не упоминают в туториалах.

Несколько моментов, которые бросились в глаза:

Сообщество стало скептически относиться к зависимостям. FluentAssertions, IdentityServer и MediatR — к ним уже нет прежнего доверия. Самый залайканный комментарий (не про библиотеку) был: «Batteries included, stay away from dependencies» (используй встроенные возможности и избегай лишних зависимостей). Этот контекст важен при чтении списка.

LINQPad — это не NuGet-пакет, но он постоянно всплывал в обсуждении. Команды строят на нём целые вспомогательные воркфлоу.

Vogen меня удивил. Type-safe value objects, генерируемые на этапе компиляции без runtime-оверхеда. Я видел баги в продакшене из-за путаницы с orderId/customerId — это как раз решает такие проблемы.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
Как версионировать Minimal API?

Нужно определить ApiVersionSet и применить его к эндпоинтам.

Более удобный подход — создать route group, назначить ему версию API, а затем использовать этот route group для маппинга отдельных эндпоинтов.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👀1
Нужно быстро написать небольшой скрипт или прототип на C#?

JetBrains Rider 2026.1 теперь поддерживает file-based C# программы, которые можно запускать без .csproj.

Доступны:

- полноценный автокомплит (code completion)
- отладка (debugging)
- run-маркеры для top-level statements и #! (shebang)

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👀2
💡Команда .NET выложила в open source свои agent skills:

Устанвока: /plugin marketplace add dotnet/skills

Одна команда — и твой coding-агент получает .NET-суперсилы

Работает в Copilot CLI, VScode, и VS 2026.

https://github.com/dotnet/skills/tree/main/plugins/dotnet-upgrade

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3😁1🥴1
Нужно предотвратить race conditions в базе данных?

Когда несколько запросов могут обновлять одни и те же строки, требуется блокировка.

Типичный пример: фоновые воркеры обрабатывают одну и ту же таблицу.

Забудьте про тяжёлые уровни изоляции. Вместо этого используйте блокировки на уровне строк:

- PostgreSQL: FOR UPDATE / FOR UPDATE SKIP LOCKED
- SQL Server: WITH (UPDLOCK)

Это можно использовать с «сырым» SQL в EF Core.

Я использовал SKIP LOCKED, чтобы масштабировать свой Outbox-процессор до более чем 2 млрд сообщений в день.

Вот как это применить в .NET: https://milanjovanovic.tech/blog/a-clever-way-to-implement-pessimistic-locking-in-ef-core

Важно отметить, что такая блокировка живёт в течение всей транзакции.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3👀2
Автор масштабировал свой outbox-процессор до более чем 2B+ сообщений в день.

Вот 4 вещи, которые он сделал:

- Добавил покрывающий индекс → index-only scan’ы
- Внедрил батчинг при публикации сообщений
- Масштабировал через параллельные процессоры
- Использовал FOR UPDATE SKIP LOCKED для обработки конкуренции

Реализовать паттерн Outbox — просто.

А вот масштабировать его — уже настоящая задача.

Полный разбор здесь

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
3👏3
Одна из самых распространенных ошибок, которые я вижу при подключении к существующим проектам:

разработчики помещают всю бизнес-логику внутрь сервисных классов.

Что это дает?

Запутанный клубок из бизнес-правил, запросов к базе данных и логики отправки email, запихнутых в один метод.

Результат:

- Новая фича ломает 3 вещи, которые ты даже не трогал.
- Тесты, где нужно 15 моков, чтобы проверить одно бизнес-правило.
- Мигрень каждый раз, когда клиент говорит: «Просто небольшое изменение…»

Корневая причина? Структура кода.

Но есть 3 простых паттерна из DDD, которые это исправляют.

Кратко, что они дают:

- Один паттерн позволяет тестировать сложные бизнес-правила без единого мока — буквально просто new Invoice() и проверка результата
- Один изолирует логику фильтрации запросов, чтобы переиспользовать ее в разных обработчиках без копирования LINQ-выражений
- Один отделяет сайд-эффекты (email, фоновые задачи, синхронизация с CRM), так что добавление нового сайд-эффекта занимает минуты, а не рефакторинг, который забивает контекст AI-агента за 5 минут

Я использовал все три на легаси-кодовой базе возрастом 7 лет.

Полные примеры кода в статье:

https://thearchitecturelab.com/post/3-ddd-patterns

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾42
Clean Architecture & Vertical Slices

Clean Architecture дает четкие границы.
Vertical Slice Architecture дает четкие фичи.
Вот как я это организую:

1) Domain — ядро бизнес-логики

Никакого EF Core. Никакого HTTP. Никаких внешних зависимостей. Только чистые бизнес-правила.

📁 Domain
├── 📁 Common
│ ├── AuditableEntity.cs
│ ├── BaseEntity.cs
│ ├── Error.cs
│ ├── PagedResult.cs
│ └── Result.cs
└── 📁 Entities
├── ApplicationUser.cs
└── TodoItem.cs


Паттерн Result, базовые сущности и доменные модели — все без привязки к фреймворкам.

2) Application — здесь раскрывается VSA

Вместо папки "Services" с 20 файлами — каждый use case имеет свою собственную папку.

📁 Application
├── 📁 Abstractions
│ ├── 📁 Data
│ │ └── IAppDbContext.cs
│ ├── 📁 Identity
│ │ ├── ICurrentUser.cs
│ │ └── ITokenService.cs
│ └── 📁 Messaging
│ ├── ICommand.cs
│ ├── ICommandHandler.cs
│ ├── IQuery.cs
│ └── IQueryHandler.cs
├── 📁 Features
│ ├── 📁 Identity
│ │ ├── 📁 Login
│ │ ├── 📁 Register
│ │ └── 📁 RefreshToken
│ └── 📁 Todos
│ ├── 📁 Create
│ │ ├── CreateTodoCommand.cs
│ │ ├── CreateTodoCommandHandler.cs
│ │ └── CreateTodoValidator.cs
└── DependencyInjection.cs


Каждый slice = Command/Query → Validator → Handler.

Хочешь понять “Create Todo”? Открываешь одну папку — и все. Без поиска по слоям.

3) Infrastructure — слой реализации

Базы данных, EF Core, кэширование, identity — все детали реализации живут здесь.

📁 Infrastructure
├── 📁 Persistence
│ ├── 📁 Configurations
│ │ ├── ApplicationUserConfiguration.cs
│ │ └── TodoItemConfiguration.cs
│ ├── 📁 Migrations
│ ├── AppDbContext.cs
│ └── AppDbSeeder.cs
├── 📁 Identity
├── 📁 Caching
└── DependencyInjection.cs


Слой Application определяет, что ему нужно (интерфейсы).
Infrastructure предоставляет реализацию. Чистая инверсия зависимостей.

4) Api — тонкий слой, без бизнес-логики

Этот слой принимает запросы и возвращает ответы. И все.

📁 Api
├── 📁 Endpoints
│ ├── TodoEndpoints.cs
├── 📁 Extensions
│ ├── GlobalExceptionHandler.cs
│ ├── ResultExtensions.cs
│ └── ValidationFilter.cs
└── Program.cs


Минимальные API с endpoint-классами.
Каждый endpoint просто валидирует запрос, передает его в handler и возвращает результат.

5) Tests — защита архитектуры

📁 tests
├── 📁 Application.UnitTests
│ └── 📁 Features/Todos
│ ├── CreateTodoCommandHandlerTests.cs
└── 📁 Architecture.Tests
└── ArchitectureTests.cs


Юнит-тесты повторяют структуру feature-папок.
Архитектурные тесты гарантируют, что зависимости всегда направлены внутрь —
Domain не ссылается на Infrastructure, Application не ссылается на Api.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍124👀2
C# модификатор in позволяет компилятору создать временную переменную для аргумента и передать на неё ссылку только для чтения.

Компилятор всегда создаёт временную переменную, если требуется преобразование аргумента, есть неявное преобразование типа аргумента, или если аргумент — это значение, а не переменная.

Пример

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8👀2
Пример итерации по словарю с деконструкцией KeyValuePair с осмысленными именами переменных вместо использования Key/Value, что делает код более читаемым.

#dotnet #csharp

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🤔4
Вашему .NET-приложению не обязательно быть медленным в 2026 году.

Кэширование — один из самых простых способов повысить производительность, и IMemoryCache — самый простой вариант, с которого можно начать:

- Очень быстрый
- Простой в использовании
- Не требует внешних зависимостей

Но есть компромиссы:

- Данные теряются при перезапуске
- Ограничено памятью одного сервера

Нужно более надёжное или масштабируемое решение?

Вот гайд по вариантам распределённого кэширования в .NET:

P.S. Не забывайте, что кэширование не решает корневую проблему производительности. Поэтому обязательно сначала проанализируйте и устраните её.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🐳2🍾21👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Docker за 2 минуты

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

У Docker есть 3 основных компонента:

1. Docker Client: место, где ты вводишь команды, которые через API общаются с Docker daemon.

2. Docker Host: здесь работает daemon, который делает всю основную работу (сборка образов, запуск контейнеров и управление ресурсами)

3. Docker Registry: хранилище Docker-образов. Docker Hub — публичный, но компании часто поднимают приватные registry.

Вот что происходит, когда ты запускаешь docker run:

• Docker подтягивает образ из registry (если его нет локально)
• Docker создаёт новый контейнер из этого образа
• Docker выделяет контейнеру файловую систему с возможностью записи (read-write)
• Docker создаёт сетевой интерфейс для подключения контейнера
• Docker запускает контейнер

Вот и всё.

Client, host и registry могут находиться на разных машинах. Именно поэтому Docker хорошо масштабируется.

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

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🕊2
Я годами использовал WebApplicationFactory и TestContainers.

Потом попробовал тестирование в .NET Aspire — и назад не вернусь.

Вот почему: тесты через WebApplicationFactory проверяют API в изоляции.
Остальные сервисы ты мокируешь.

Это значит, что ты никогда не ловишь баги, которые возникают при взаимодействии сервисов A и B в проде.

Традиционный сетап выглядит так:

→ Прямая ссылка на проект API
→ Ручной подъём Docker-контейнеров через TestContainers
→ Переопределение connection string через переменные окружения
→ Мок внешних сервисов, от которых зависит API
→ Надежда, что в проде всё будет работать вместе

Слишком много glue-кода ради одного теста.

.NET Aspire поднимает ВСЮ распределённую систему в рамках одного теста:
→ Все API запущены
→ Реальные контейнеры PostgreSQL и Redis
→ Реальные HTTP-вызовы между сервисами
→ Ноль моков

Вот 3 конкретных плюса, которые я получил сразу:

𝟭. Больше нет boilerplate с TestContainers

Раньше: 50+ строк на конфигурацию PostgreSQL-контейнера, connection string и переменных окружения.

Теперь: одна строка — ссылка на AppHost.
Aspire делает всё сам.

𝟮. Тесты поймали ломающее изменение API-контракта

Products API изменил модель ответа.
С моками тесты всё ещё проходили.

С Aspire — Stocks API сразу упал, потому что не смог десериализовать ответ. Поймали до продакшена.

𝟯. Порядок старта сервисов автоматический

Больше нет случайных падений тестов из-за того, что API стартовал раньше, чем PostgreSQL был готов. Aspire автоматически ждёт зависимости.

Завтра я отправлю полный гайд для 25,149+ .NET-разработчиков:

- Точный сетап DistributedApplicationTestingBuilder, который я использую
- Как шарить один инстанс приложения на 100+ тестов (сильный буст скорости)
- Моя стратегия очистки базы, которая предотвращает «загрязнение» тестов
- 2 продвинутых паттерна: тестирование фоновых задач и очередей сообщений

Это тот подход к тестированию, который наконец сделал распределённые системы тестируемыми.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍5🕊2
5 Архитектурных Тестов Необходимых Каждому .NET-Проекту.

Каждый проект начинается с благих намерений. Вы согласовываете границы слоёв, соглашения об именовании, направление зависимостей. Через полгода кто-то переносит доменный сервис в проект инфраструктуры, обработчик получает имя не по соглашению или внутренний класс становится публичным, потому что это значение по умолчанию. Архитектурные тесты предотвращают это. Они превращают архитектурные правила в автоматизированные тесты, которые запускаются в CI. Вот архитектурные тесты, которые пригодятся каждому проекту.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
1👏1
Перестань дублировать JOINы — используй USING

Если ты давно пишешь SQL-запросы, ты, скорее всего, привык к ON. Он работает. Но когда ты джоинишь две таблицы по колонкам с одинаковыми именами, есть более чистый и элегантный способ — USING.

Вот почему стоит на него перейти.

SELECT 
e.Employee_ID,
e.Employee_Name,
e.Department,
s.Net_Sales
FROM Employees e
JOIN sales s
ON e.Employee_ID = s.Employee_ID


ON работает, но он многословный. Приходится повторять имена таблиц и колонок. Если имя колонки одинаковое в обеих таблицах, ты фактически пишешь одно и то же дважды. Хуже того, при выборке ты получишь два столбца Employee_ID, если явно их не квалифицировать.

USING — это сокращённая форма для JOIN по равенству колонок с одинаковыми именами. Тот же запрос:

SELECT 
e.Employee_ID,
e.Employee_Name,
e.Department,
s.Net_Sales
FROM Employees e
JOIN sales s
USING (Employee_ID);


Гораздо чище, правда? USING автоматически сопоставляет колонки с одинаковым именем и выполняет INNER JOIN (или LEFT/RIGHT JOIN — в зависимости от типа соединения). Ты указываешь имя колонки только один раз.

Использование USING — небольшое изменение, которое делает SQL более лаконичным и самодокументируемым. Это снижает вероятность ошибок и делает результирующие наборы данных чище.

Убедись, что твоя СУБД поддерживает USING.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
13👎3😁1
Agent Framework: фоновые ответы решают проблему таймаутов у долгоживущих агентов

Агенты, использующие reasoning-модели, могут выполнять задачу несколько минут — глубокое исследование, многошаговый анализ, генерация объёмного контента. Держать HTTP-соединение открытым всё это время ненадёжно: балансировщики нагрузки рвут соединение по таймауту, мобильные клиенты отваливаются, и любая ошибка приводит к потере всего накопленного прогресса.

Фоновые ответы в Microsoft Agent Framework позволяют вынести такие долгие операции в background, чтобы приложение оставалось отзывчивым и устойчивым независимо от того, сколько времени агенту нужно на выполнение задачи.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👏1
Улучшения в EF Core 11 Preview 2 для SQL Server

▪️Поддержка операторов MaxBy() и MinBy() в LINQ-запросах.

▪️Интеграция с векторными индексами SQL Server DiskANN и новой функцией VECTOR_SEARCH(), что позволяет реализовать высокопроизводительный поиск по векторному сходству.

▪️Создание полнотекстовых каталогов и индексов SQL Server напрямую из EF Core.
Поддержка функций полнотекстового поиска FREETEXTTABLE() и CONTAINSTABLE().

▪️Поддержка JSON_CONTAINS() для упрощения запросов к JSON-данным, хранящимся в SQL Server.

EF Core 11 требует .NET 11 SDK.

https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-11.0/whatsnew

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾1
Секрет: как устранить 99% NullReferenceException

Немногие разработчики об этом знают.

Но это может полностью изменить то, как вы пишете код на C#.

NullReferenceException — самая частая runtime-ошибка в проектах на .NET.

И обычно она возникает в самый неподходящий момент — уже в продакшене.

Большинство разработчиков исправляют NullReferenceException постфактум.

Опытные — предотвращают их появление заранее.

Почти все такие ошибки можно убрать с помощью двух простых настроек проекта.

Добавьте это в ваш .csproj:

<PropertyGroup>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>


Как это работает:

Nullable включает статический анализ null-ссылок в C#:
↳ предупреждает о потенциальных null-проблемах
↳ заставляет явно обрабатывать nullable-типы
↳ делает работу с null явной в коде

TreatWarningsAsErrors превращает предупреждения в ошибки сборки:
↳ проект не скомпилируется, пока не исправлены null-проблемы (и другие warnings)
↳ ошибки ловятся на этапе разработки, а не в продакшене

Совет:

Можно добавить эти настройки в файл Directory.Build.props (рядом с .sln) — тогда они применятся ко всем проектам в решении.

Вместе эти настройки смещают проблемы с null
с runtime → на этап компиляции.

Так и устраняется 99% NullReferenceException в проектах.

Это одна из самых «выгодных» настроек в .NET по соотношению эффект/затраты.

В следующий раз при создании проекта — начните именно с этого.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🥴74🤔2
SSO — это процесс аутентификации, который позволяет пользователям получать доступ к нескольким приложениям с помощью одного основного ключа.

Это реализуется с использованием централизованного сервера аутентификации, который хранит учётные данные пользователя и проверяет их для каждого приложения.

Вот какие шаги происходят, если вы хотите войти в веб-приложение Trello, используя аккаунт Google:

1. Открываете страницу входа Trello и выбираете Google как способ авторизации
2. Trello перенаправляет пользователя на страницу входа Google
3. Пользователю отображается страница входа Google
4. Пользователь вводит свои учётные данные Google
5. Google отправляет информацию аутентификации на сервер авторизации SSO
6. Если учётные данные валидны, сервер авторизации возвращает токен аутентификации (SAML)
7. Google отправляет токен аутентификации в Trello
8. На последнем шаге Trello отправляет токен на сервер аутентификации Google для его валидации
9. Если токен валиден, Trello предоставляет пользователю доступ и сохраняет сессию для последующих взаимодействий

Преимущества SSO:

- Улучшенный пользовательский опыт. Пользователю не нужно запоминать несколько логинов и паролей.
- Повышенная безопасность. Пользователи реже переиспользуют пароли в разных приложениях.

Недостатки:

- Единая точка отказа. Один из ключевых минусов — SSO создаёт single point of failure. Если система SSO скомпрометирована, злоумышленник может получить доступ ко всем подключённым приложениям и сервисам.
- Риски безопасности. Если учётные данные скомпрометированы, под угрозой оказываются все связанные приложения.

Некоторые распространённые типы SSO:

- SAML-based SSO. Самый распространённый тип SSO. Использует протокол SAML для обмена данными аутентификации между SSO-сервером и приложениями.
- OpenID Connect. Более новый тип SSO, основанный на OAuth 2.0. Проще по сравнению с SAML и легче интегрируется с веб-приложениями.

И популярные решения SSO:

- Azure Active Directory
- Okta
- Ping Identity
- OneLogin
- Google Cloud Identity Platform

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
7👏2🥴1
This media is not supported in your browser
VIEW IN TELEGRAM
Кто-то сделал веб-симулятор System Design.

Называется Paperdraw. Он позволяет перетаскивать компоненты (drag & drop) и в реальном времени смотреть, как они ведут себя при реальных условиях: нагрузке, сбоях, задержках и масштабировании.

100% бесплатно можно попробовать.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
11🔥4👍3👏1
10 скрытых фич EF Core, которые используют сеньоры

1️⃣Shadow Properties
EF Core позволяет добавлять свойства, которых нет в классе, но которые присутствуют в базе данных.
Идеально подходят, например, для хранения данных аудита, не засоряя сущности лишними полями.

2️⃣Query Tags
Можно легко добавлять комментарии к SQL-запросам, которые генерирует EF Core.
Удобно при профилировании - в логах SQL сразу видно, откуда пришёл тот или иной медленный запрос.

3️⃣Compiled Queries
Часто используемые запросы можно скомпилировать заранее, чтобы не тратить ресурсы на парсинг каждый раз.
Повышает производительность при большом числе однотипных запросов.

4️⃣DbContext Pooling
Вместо того чтобы каждый раз создавать новый DbContext, можно переиспользовать уже созданные.
Существенно снижает потребление памяти и повышает производительность.

5️⃣Value Converters
Позволяют автоматически преобразовывать значения между .NET и базой данных.
Полезно для хранения кастомных типов, enum'ов и Value Object'ов.

6️⃣Temporal Tables
Позволяют отслеживать историю изменений данных прямо в базе.
Удобно для аудита, отката изменений и анализа исторических данных.

7️⃣Database Seeding
EF Core 9 добавил новые методы UseSeeding, UseAsyncSeeding для удобного наполнения базы начальными данными.

8️⃣Split Queries for Includes
Позволяет разбивать сложные запросы с Include на несколько простых.
Избегает проблем с громоздкими JOIN’ами и повышает производительность.

9️⃣Raw SQL Queries
Можно выполнять чистый SQL прямо из EF Core.
Полезно, когда нужно выжать максимум производительности или использовать специфичный функционал конкретной СУБД.

1️⃣0️⃣Миграции для нескольких баз данных
Можно легко управлять миграциями и схемами сразу для разных провайдеров.
Подходит для приложений, которые должны работать с несколькими СУБД (например, SQL Server, PostgreSQL, MySQL).

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾43🥴1