C# Portal | Программирование
13.3K subscribers
1.28K photos
131 videos
31 files
994 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

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

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
Как быстрее всего выполнить массовую вставку данных в SQL?
Независимо от того, разрабатываете ли вы платформу для аналитики данных, переносите legacy-систему или подключаете большой поток новых пользователей, в какой-то момент вам, скорее всего, понадобится вставить в базу данных огромный объем данных.

Поэтому важно понимать, какие техники быстрой массовой вставки доступны в C# и EF Core.
EF Core — вполне приемлемый вариант. Он предлагает привычный developer experience, и хотя его производительность не самая высокая, для вашего сценария ее может быть достаточно.

Если нужна более высокая производительность, еще один вариант — библиотека EF Bulk Extensions. Работа с ней по-прежнему ощущается как работа с EF, и это дополнительный плюс.

Все еще нужны более быстрые вставки? Тогда ваш выбор — SqlBulkCopy. Это самый быстрый способ вставить большой объем данных в SQL Server. В PostgreSQL есть команда COPY, которая работает схожим образом.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51🍾1
Я добавил одну строку, чтобы сделать моё приложение с Azure SQL надёжнее.

Она сразу же сломала все транзакции в моём коде.

Вот что произошло.

Azure SQL — это общая мультитенантная служба. Она может кратковременно разрывать подключения во время аварийного переключения, масштабирования и скачков нагрузки.

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

На локальном SQL Server вы почти никогда с ними не сталкиваетесь. В облаке это нормальное явление.

EF Core решает эту проблему одной строкой:

→ EnableRetryOnFailure(maxRetryCount: 5)

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

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

Но есть одна ловушка, о которой никто не предупреждает.

Как только вы включаете повторные попытки, эта строка начинает выбрасывать исключение:

→ using var tx = context.Database.BeginTransaction();

Почему? Стратегия повторных попыток должна иметь возможность повторно выполнить ВСЮ операцию как единое целое.

Транзакция, созданная вручную, охватывает только часть вашего кода. EF Core не может безопасно повторно выполнить половину операции, поэтому не позволяет запускать транзакцию таким способом.

Решение — обернуть работу в стратегию выполнения:

→ var strategy = context.Database.CreateExecutionStrategy();
→ await strategy.ExecuteAsync(async () => { ... ваша транзакция здесь ... });

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

На этой детали спотыкается почти каждая команда, которая переносит EF Core в облако.

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

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

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾2
image_2026-07-14_07-07-25.png
1.3 MB
Инвалидация кеша: почему удаление данных — одна из самых сложных задач в разработке программного обеспечения

Кеширование делает приложения быстрыми.
Но рано или поздно каждая система сталкивается с одним вопросом:
Что происходит, когда исходные данные изменяются?
Именно здесь начинается инвалидация кеша.

Что такое инвалидация кеша?
Представьте такой поток запроса:

Пользователь


Кеш Redis


База данных

Первый запрос:
> Промах кеша
> Чтение из базы данных
> Сохранение в Redis

Все последующие запросы выполняются быстро.
До тех пор, пока...
Данные не изменятся.

Пример
Товар стоит: ₹999
Значение закешировано в Redis.
Позже...
Администратор обновляет цену: ₹899
Теперь в базе данных хранится новая цена.
Но Redis по-прежнему возвращает: ₹999
Пользователи видят устаревшую информацию.

Почему это сложно? Все кешированные копии должны оставаться синхронизированными.
Иногда в системе используются:
> Кеш браузера
> CDN
> Redis
> Память приложения

Одно обновление может потребовать инвалидации данных сразу в нескольких местах.

Распространённые стратегии инвалидации кеша

1. Time-To-Live (TTL)
TTL = 10 минут
Кеш автоматически истекает.
Просто.
Но до истечения срока действия пользователи могут видеть устаревшие данные.

2. Удаление при обновлении
При каждом изменении базы данных:

Обновление БД

Удаление кеша

Следующий запрос заново создаёт запись в кеше.
Это один из самых распространённых подходов.

3. Write-Through Cache
При каждой операции записи обновляются:
> База данных
> Кеш
Они остаются синхронизированными.

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

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

Без инвалидации кеша:
> Веб-сайт → ₹999
> Мобильное приложение → ₹999
> База данных → ₹899
Клиенты получают несогласованную информацию.

Распространённые ошибки
Забывают инвалидировать кеш
Устанавливают слишком большие значения TTL
Кешируют часто изменяющиеся данные
Обновляют базу данных, но не кеш

Главный выводs
> Кеширование делает системы быстрыми.
> Инвалидация кеша обеспечивает корректность данных.
> Кеш, который никогда не истекает, рано или поздно становится некорректным.
> Завтра мы разберём разные стратегии кеширования:
> Cache-Aside, Read-Through, Write-Through и Write-Back

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
7🍾2
Служебные учётные записи задают контекст безопасности, который службы Windows, запланированные задачи и приложения используют для доступа к локальным и сетевым ресурсам.

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

https://learn.microsoft.com/en-us/training/modules/understand-windows-service-accounts/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2
В .NET есть коллекция, из которой данные читаются в 2–4 раза быстрее, чем из Dictionary

Большинство разработчиков ни разу её не использовали.

Она называется FrozenDictionary — а для множеств есть FrozenSet. Обе коллекции появились в .NET 8.

Идея простая:

> Создаёте коллекцию один раз, читаете из неё много раз и больше никогда не изменяете.

Такие данные наверняка уже есть в ваших проектах:

- коды стран;
- названия ролей;
- feature flags;
- разрешённые расширения файлов.

Вы загружаете их при старте приложения и больше не меняете.

Но обычный Dictionary об этом не знает.

Он по-прежнему готов к добавлению и удалению элементов, а также к изменению размера — операциям, которые вы никогда не выполните. За эту гибкость приходится платить при каждом чтении.

Почему Frozen-коллекции быстрее

Когда вы вызываете ToFrozenDictionary, .NET тратит дополнительное время на анализ данных.

После этого он выбирает наиболее подходящую внутреннюю структуру:

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

Вы один раз платите за создание коллекции и затем постоянно получаете более быстрые операции чтения.

Компромисс простой:

- создание медленнее в 2–10 раз;
- чтение быстрее в 2–4 раза, а для строк выигрыш может быть ещё больше.

Когда использовать

- Для lookup-таблиц, которые загружаются при старте и больше не изменяются.
- Вместо длинного switch по строковым литералам — например, с проверкой через Contains.
- Для любой коллекции с большим количеством операций чтения, которая создаётся один раз на запрос.

Когда не использовать

- Если коллекция должна изменяться после создания: методов Add и Remove нет.
- Если данные будут прочитаны всего несколько раз.
- Если проект всё ещё работает на .NET 7 или более старой версии.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍113🍌2🍾1
.NET 11 Preview 6 включает Extension Indexers из C# 15.

Например, теперь можно расширять такие типы, как IReadOnlyList<T>, чтобы получать последний элемент через ^1 — без изменения самой коллекции и без дублирования вспомогательной логики.
Более выразительный код и более естественные API.

#dotnet #CSharp #NET11

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍3🍾2
This media is not supported in your browser
VIEW IN TELEGRAM
Postgres 19 обрабатывает всплески нагрузки так, как и должна работать инфраструктура.

Не за счёт одного фиксированного пула I/O-воркеров, рассчитанного на некий вымышленный «средний» день.

А динамически.

→ Нагрузка резко растёт
→ Очередь операций ввода-вывода увеличивается
→ PostgreSQL это замечает
→ Запускаются дополнительные воркеры
→ Очередь разгружается
→ Когда нагрузка снижается, лишние воркеры завершают работу

Без ручного вмешательства.
Без постоянного избыточного резервирования ресурсов.

И без крошечного пула воркеров, который захлёбывается под продакшен-нагрузкой.

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

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🍾2
Паттерн Options в .NET — это одна из тех фич, которые я стабильно использую во всех своих C#-проектах

Более чистое управление конфигами
Сильно типизированные классы
Простая интеграция с DI
Без проблем работает с appsettings.json, secrets.json, Azure Key Vault и прочим

Почему это важно

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

Обычно это выглядит так

🔹Определяешь конфиг в appsettings.json
🔹Создаёшь POCO-класс
🔹Биндишь его через .AddOptions<T>().BindConfiguration()
🔹Инжектишь в сервисы через IOptions<T>

Просто. Масштабируемо. Аккуратно.

А ты используешь этот паттерн у себя или до сих пор дёргаешь значения конфигов через IConfiguration["key"] 😃

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥32🍾1
using var client = new HttpClient(); внутри цикла выглядит как ответственное управление ресурсами. На деле это утечка сокетов.

Каждый новый экземпляр HttpClient создаёт собственный пул соединений, а после вызова Dispose сокеты остаются в состоянии TIME_WAIT примерно на четыре минуты. Под нагрузкой доступные порты заканчиваются, и вы получаете SocketException, хотя сервер полностью исправен.

Вместо этого внедрите IHttpClientFactory. Одна строка — и проблема решена.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍4🍾2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🍾1
Большинство senior-разработчиков советуют создавать репозитории для EF Core.

Но это не лучший подход к написанию кода.

По мере роста .NET-проектов работа с данными становится всё сложнее.

Многие команды начинают с паттерна Repository, оборачивая в него запросы EF Core.

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

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

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

Помните, что DbContext в EF Core уже реализует паттерны Repository и Unit of Work.

Это прямо указано в официальной документации Microsoft по DbContext. То же самое можно увидеть в описании класса DbContext в вашей IDE.

Создавая репозиторий поверх EF Core, мы создаём абстракцию над абстракцией, что приводит к чрезмерно усложнённым решениям.

Как решить эту проблему? Ответ — паттерн 𝗦𝗽𝗲𝗰𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻.

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

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

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👎41🍾1
Файловые приложения поддерживают ссылки на .dll через #:include.
Начиная с .NET 11 Preview 6

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍3🥰1🍾1
Не начинайте с микросервисов.

Даже если вы уверены, что ваше приложение вырастет настолько, что такой подход будет оправдан.

И вот почему.

У микросервисов есть своя цена:

* Координация между командами
* Работа со сбоями
* Eventual consistency
* Автоматизация деплоя
* Управление несколькими сервисами
* Развёртывание дополнительной инфраструктуры

В начале нового проекта эта сложность вам не нужна.

Даёт ли она ценность пользователям? Скорее всего, нет.

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

Если вы не умеете управлять большим монолитом, с микросервисами лучше не станет.

Определение границ сервисов требует большой работы. Насколько вы уверены, что сможете правильно провести их с самого начала?

Если вы ошибётесь, рефакторинг границ сервисов будет сложным. В монолите это сделать гораздо проще.

Вот менее рискованная стратегия:

* Начните с монолита
* Определите границы сервисов — bounded contexts
* Затем решите, действительно ли их нужно выделять в микросервисы

Есть и множество других факторов. Все их невозможно уместить в одном посте.

Но надеюсь, я дал вам пищу для размышлений.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾1
Microsoft подтвердила «значительное ускорение» поиска по разделу «Этот компьютер» в Проводнике Windows 11.

Маркус Эш, руководитель направления дизайна и исследований Windows, подтвердил, что улучшения скорости и релевантности, которые Microsoft внедряет в Windows Search, следующим этапом появятся в Проводнике. В первую очередь речь идёт о «значительном ускорении» поиска по всему разделу «Этот компьютер».

Это важно, потому что сейчас поиск по разделу «Этот компьютер» работает мучительно медленно.

Я протестировал поиск одного и того же файла через Windows Search и Проводник. Windows Search нашёл его примерно за секунду.

Поиск в Проводнике по всему разделу «Этот компьютер» занял более 8 минут.

И это был не перегруженный компьютер с тысячами файлов. Это был практически чистый тестовый ПК, на который почти ничего не было загружено.

Windows Search уже стал заметно лучше: более чистый интерфейс, меньше отвлекающих элементов, приоритет локальных результатов, обработка опечаток, поиск файлов по двум символам, поиск по подстроке и переключатель для отключения рекомендаций Bing и Microsoft Store.

Теперь эти улучшения поиска файлов наконец появятся и в Проводнике...

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯8🥴4😁3🍾1
Совет по Minimal API 💡

Как сделать обработчик чище?

Minimal API — это новый и лаконичный способ создавать REST API в .NET.

Один endpoint состоит из:

* extension-метода, соответствующего HTTP-методу
* маршрута
* обработчика

Обработчики часто пишут прямо в теле endpoint, но такой подход подходит только для простых случаев.

Что делать, когда код разрастается и становится перегруженным?

Использовать локальные функции.

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

В результате endpoints становятся чище, а логика оказывается инкапсулирована в одном месте.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
6🤔1🏆1🍾1
Я часто слышу, что C# — мусор и что с ним не стоит работать.

Вот почему, на мой взгляд, он лучше, чем считают некоторые:
В backend-разработке и CPU-intensive сценариях C# может быть значительно быстрее интерпретируемых языков и языков с динамической типизацией.

C# превосходит Python по скорости. Python-код обычно выполняется построчно во время работы программы, тогда как C# заранее компилируется, а затем дополнительно оптимизируется во время выполнения. У него очень эффективный runtime.
В CPU-intensive задачах и высоконагруженных backend-системах C# часто превосходит JavaScript и Node.js.

По производительности C# и Java обычно идут примерно на одном уровне.
Сравнение C# и Go неоднозначно. Go отлично подходит для сервисов, но C# предлагает более богатую экосистему, более продвинутые оптимизации runtime и мощные возможности языка.

C++ и Rust обычно быстрее C#, когда в приоритете максимальная производительность и полный контроль над памятью.

Но это лишь часть картины.

Что предлагает C#:
Производительность
Продуктивность разработчика
Строгая типизация
Поддерживаемость кода
Безопасная работа с памятью
Зрелая экосистема

JIT-компиляция оптимизирует участки кода, которые выполняются чаще всего.
Предварительная компиляция позволяет сократить время запуска и потребление памяти.
Сборщик мусора эффективно работает в приложениях с высокой пропускной способностью.
Разработчики могут использовать API вроде Span<T> и pipelines, чтобы уменьшать количество аллокаций и работать ближе к памяти.

Также C# позволяет создавать масштабируемые приложения, способные обрабатывать тысячи одновременных I/O-операций с помощью async и await.

Наконец, C# подходит для разработки самых разных типов приложений:
> ASP.NET Core — для Web API и backend-систем
> облачные сервисы и распределённые приложения
> WPF, WinUI и .NET MAUI — для desktop-приложений
> кроссплатформенные мобильные приложения
> игры на Unity
> background workers, планировщики и системы автоматизации
> AI-приложения и обработка данных с ML.NET

На C# также можно создавать serverless-функции, IoT-решения, CLI-инструменты, приложения реального времени и высокопроизводительные сетевые сервисы.

C# не всегда оказывается самым быстрым языком в каждом бенчмарке.
Но для многих реальных приложений он предлагает одно из лучших сочетаний производительности, продуктивности, инструментов и зрелости экосистемы.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍212🍾2
Поддержка .NET 8 заканчивается через четыре месяца

10 ноября 2026 года Microsoft прекратит поддержку .NET 8, поэтому уже сейчас стоит планировать переход на .NET 10.
.NET 10 относится к LTS-релизам и будет получать обновления до 14 ноября 2028 года.

Одно из главных изменений — заметный прирост производительности ASP.NET Core. По сравнению с .NET 8 он способен обрабатывать на 15% больше запросов в секунду. Для Minimal APIs потребление памяти также снизилось на 93%, что значительно уменьшает общий working set приложения.

Что нового появилось в .NET 10:

C# 14
В язык добавили extension members, присваивание через null-conditional оператор, ключевое слово field, модификаторы параметров в лямбда-выражениях, а также partial-конструкторы и события.

Файловые приложения
Теперь небольшой C#-код можно запускать прямо из одного файла .cs, без создания .sln и .csproj.

ASP.NET Core
Minimal APIs получили встроенную валидацию и поддержку JSON Patch. Также появились Server-Sent Events и поддержка OpenAPI 3.1.

EF Core
Добавлены опциональные complex types, поддержка JSON и структур, операторы LeftJoin и RightJoin, именованные query-фильтры и расширенные возможности ExecuteUpdate.

.NET Aspire
В Aspire 9.5 появился отдельный CLI, поддержка файлового AppHost, визуализатор генеративного ИИ, улучшенная трассировка, интеграция с хостингом OpenAI и поддержка эмуляторов Azure.

Blazor
Для Blazor WebAssembly добавили Hot Reload, настройку окружения, профилирование производительности и диагностические счётчики. Также улучшили роутинг, предварительную загрузку статических ресурсов и валидацию форм.

Библиотеки и Runtime
Появились новые API для криптографии, сериализации, коллекций, диагностики, числовых операций и работы с ZIP-файлами. Runtime получил улучшения JIT, NativeAOT, девиртуализации методов, стековых аллокаций и генерации кода, а также поддержку AVX10.2.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
2🍾1
Большинство разработчиков неправильно подходят к оптимизации SQL-запросов

Часто разработчики часами переставляют условия в WHERE, переписывают IN на EXISTS или добавляют query hints. Но в большинстве случаев это почти не влияет на производительность.

Современные СУБД и так умеют самостоятельно менять порядок JOIN и применять фильтры как можно раньше. Поэтому важнее не то, как именно записан запрос, а может ли база эффективно использовать индексы и правильно оценить объём данных.

Основной прирост скорости обычно дают три вещи.

Во-первых, фильтры должны позволять использовать индекс.
Например, если применить функцию к индексируемому столбцу:
EXTRACT(YEAR FROM order_date) = 2025
база может отказаться от использования индекса. Гораздо эффективнее задать диапазон по самому столбцу с датой.

Во-вторых, нужно правильно подбирать индексы.
В первую очередь стоит индексировать столбцы, которые участвуют в WHERE, JOIN и ORDER BY. При этом один составной индекс, например (status, order_date), часто работает лучше двух отдельных.

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

Поэтому важнее правильно настроить индексы и статистику, чем бесконечно переписывать сам запрос.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍1👏1🍾1
Чувак рассказывает, как провалил техническое интервью из-за оптимизации одного отчётного запроса.
На маленьком объёме данных всё выглядело нормально: запрос выполнялся быстро. Но на тестовой базе с 500 000 строк он внезапно стал очень медленным.

Причина — скрытая проблема N+1: внутри SELECT был подзапрос, который выполнялся заново для каждой строки результата. То есть вместо одного обращения к базе происходили сотни тысяч повторных операций.

Решение оказалось простым — заменить такие подзапросы на JOIN, чтобы база могла обработать данные одним проходом.

Ещё одна частая ошибка — несколько одинаковых подзапросов для расчёта разных метрик. Например, отдельно считать сумму покупок клиента и количество заказов. Вместо этого лучше один раз собрать агрегированные данные через CTE, а потом присоединить результат.

Главный вывод: SQL, который летает на сотне строк, может полностью сломаться на больших данных. Оптимизацию нужно проверять не только на локальных тестах, но и на реальных объёмах.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣6👍4🤯1🍾1
В .NET долгое время одним из самых удобных инструментов для организации CQRS и разделения логики был MediatR, он помогал структурировать команды и запросы, разгружал API слой и снижал связанность кода. Многие проекты, особенно с архитектурой Vertical Slice, держались на нём годами.

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

Альтернатива, которая решает эти проблемы, — переход на простые ручные обработчики. Такой подход убирает лишнюю рефлексию и декораторы, упрощает трассировку, а IDE быстрее находит нужный участок кода.

Вот гайд как выстроить систему, где:

> Стартовая реализация использует MediatR, а затем заменяется на ручные обработчики

> Регистрация обработчиков происходит автоматически

> Уведомления обрабатываются без MediatR Notifications

> Общая функциональность (логирование, валидация, транзакции) подключается без лишней обвязки

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

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
5🤨1🍾1