Как создавать фоновые задачи в .NET?
С Quartz это так же просто, как реализовать интерфейс.
Вы можете внедрять любые необходимые зависимости через DI. Фоновые задачи также имеют scoped-область, поэтому можно даже внедрять DbContext.
👉 @KodBlog
С Quartz это так же просто, как реализовать интерфейс.
Вы можете внедрять любые необходимые зависимости через DI. Фоновые задачи также имеют scoped-область, поэтому можно даже внедрять DbContext.
[DisallowConcurrentExecution]
public class MyBackgroundJob : IJob
{
public MyBackgroundJob(...)
{
}
public async Task Execute(IJobExecutionContext context)
{
// Implement your logic here.
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2😁2👨💻1
Сделать столбец Sparse в Entity Framework 💡
В SQL Server sparse-столбцы — это обычные столбцы, оптимизированные для хранения значений
Хорошими кандидатами для sparse-столбцов являются любые столбцы, у которых в большинстве строк вероятно будет значение
и т. д.
Sparse-столбцы легко настраиваются в EF
👉 @KodBlog
В SQL Server sparse-столбцы — это обычные столбцы, оптимизированные для хранения значений
NULL. Их использование может значительно экономить место.Хорошими кандидатами для sparse-столбцов являются любые столбцы, у которых в большинстве строк вероятно будет значение
NULL, например:dateAccountClosed
discountAmount
Suffix
Address4
DeliveryInstructions
OrderReturnDate
и т. д.
Sparse-столбцы легко настраиваются в EF
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👏1
This media is not supported in your browser
VIEW IN TELEGRAM
REST API vs WebSocket
REST API:
- Модель запрос–ответ
- Клиент отправляет запрос → сервер возвращает ответ
- Stateless (каждый запрос независим)
- Лучше всего подходит для CRUD-операций
- Использует HTTP/HTTPS
• Пример: получение данных пользователя, отправка форм
WebSocket:
- Двусторонняя связь в реальном времени
- Постоянное full-duplex соединение
- Stateful-соединение
- Лучше всего подходит для live-обновлений
- Использует протокол ws/wss
• Пример: чат-приложения, лайв-трейдинг, онлайн-игры
🟢 REST = запросил → получил
🔵 WebSocket = постоянное соединение и обмен данными в любой момент
👉 @KodBlog
REST API:
- Модель запрос–ответ
- Клиент отправляет запрос → сервер возвращает ответ
- Stateless (каждый запрос независим)
- Лучше всего подходит для CRUD-операций
- Использует HTTP/HTTPS
• Пример: получение данных пользователя, отправка форм
WebSocket:
- Двусторонняя связь в реальном времени
- Постоянное full-duplex соединение
- Stateful-соединение
- Лучше всего подходит для live-обновлений
- Использует протокол ws/wss
• Пример: чат-приложения, лайв-трейдинг, онлайн-игры
Please open Telegram to view this post
VIEW IN TELEGRAM
👏7❤2
FluentValidation делает валидацию входных данных очень простой.
Знали ли вы, что валидаторы поддерживают DI (Dependency Injection)?
Вы можете внедрять объекты настроек, сконфигурированные через DI, и использовать их внутри валидаторов.
Посмотрите пример в сниппете кода ниже.👇
Знали ли вы, что валидаторы поддерживают DI (Dependency Injection)?
Вы можете внедрять объекты настроек, сконфигурированные через DI, и использовать их внутри валидаторов.
Посмотрите пример в сниппете кода ниже.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🥴1
Непопулярное мнение:
Большинство разработчиков на самом деле не понимают Git.
Они знают только три команды:
1.
2.
3.
Но Git может гораздо больше:
- ветвление (branching)
- rebase
- stash
- cherry-pick
- разрешение конфликтов (conflict resolution)
Правильное понимание Git может сэкономить часы отладки и исправления сломанных веток.
👉 @KodBlog
Большинство разработчиков на самом деле не понимают Git.
Они знают только три команды:
1.
git add2.
git commit3.
git pushНо Git может гораздо больше:
- ветвление (branching)
- rebase
- stash
- cherry-pick
- разрешение конфликтов (conflict resolution)
Правильное понимание Git может сэкономить часы отладки и исправления сломанных веток.
Please open Telegram to view this post
VIEW IN TELEGRAM
😐21🥴5❤1👎1
Используешь ли ты trunk-based development?
Это стратегия ветвления, при которой все разработчики работают напрямую в «trunk» (основной ветке).
Feature flags — обязательная часть такого подхода.
Незавершённые фичи прячутся за feature flag и выкатываются только тогда, когда они готовы.
👉 @KodBlog
Это стратегия ветвления, при которой все разработчики работают напрямую в «trunk» (основной ветке).
Feature flags — обязательная часть такого подхода.
Незавершённые фичи прячутся за feature flag и выкатываются только тогда, когда они готовы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤔3❤1
Алгоритм ограничения запросов: Sliding Window Counter
Этот алгоритм — комбинация Fixed Window и Sliding Window.
То есть есть фиксированные окна, но поверх них «скользит» sliding window, которая постоянно проверяет, что текущее окно не превышает допустимое количество запросов (rate limit).
Базовая идея:
Например:
Как видно, есть два фиксированных окна и одно скользящее окно поверх них, которое отслеживает количество запросов внутри себя.
Это значит, что учитываются запросы как из предыдущего окна, так и из текущего — но только та их часть, которая попадает внутрь sliding window. И алгоритм следит, чтобы суммарное число запросов не превышало заданный лимит.
Формула:
Для overlap (перекрытия):
Объяснение overlap:
Представим два окна:
-> 1-е окно: с 1s до 10s
-> 2-е окно: с 10s до 20s
Допустим, мы находимся на 13-й секунде (то есть на 3 секунде второго окна).
Если смотреть назад, sliding window охватывает интервал от 3s до 13s (то есть захватывает 3 секунды из первого окна).
Часть предыдущего окна, которая попадает в sliding window — это промежуток с 3s до 10s. Это и есть overlap.
Соответственно:
-> берём запросы за последние 7 секунд из предыдущего окна (3s–10s)
-> и добавляем запросы за текущие 3 секунды из нового окна (10s–13s)
После этого проверяем: если суммарное количество превышает лимит — отклоняем запрос.
В итоге:
это всегда sliding window длиной, например, 10 секунд, которая «плавает» поверх фиксированных окон и динамически проверяет количество запросов.
Да, разобраться в этом не с первого раза — нормально🙂
👉 @KodBlog
Этот алгоритм — комбинация Fixed Window и Sliding Window.
То есть есть фиксированные окна, но поверх них «скользит» sliding window, которая постоянно проверяет, что текущее окно не превышает допустимое количество запросов (rate limit).
Базовая идея:
Например:
Как видно, есть два фиксированных окна и одно скользящее окно поверх них, которое отслеживает количество запросов внутри себя.
Это значит, что учитываются запросы как из предыдущего окна, так и из текущего — но только та их часть, которая попадает внутрь sliding window. И алгоритм следит, чтобы суммарное число запросов не превышало заданный лимит.
Формула:
effective_requests = current_window_count +
(previous_window_count × overlap_fraction)
Для overlap (перекрытия):
overlap_fraction =
remaining_time_in_previous_window / window_size
Объяснение overlap:
Представим два окна:
-> 1-е окно: с 1s до 10s
-> 2-е окно: с 10s до 20s
Допустим, мы находимся на 13-й секунде (то есть на 3 секунде второго окна).
Если смотреть назад, sliding window охватывает интервал от 3s до 13s (то есть захватывает 3 секунды из первого окна).
Часть предыдущего окна, которая попадает в sliding window — это промежуток с 3s до 10s. Это и есть overlap.
Соответственно:
-> берём запросы за последние 7 секунд из предыдущего окна (3s–10s)
-> и добавляем запросы за текущие 3 секунды из нового окна (10s–13s)
После этого проверяем: если суммарное количество превышает лимит — отклоняем запрос.
В итоге:
это всегда sliding window длиной, например, 10 секунд, которая «плавает» поверх фиксированных окон и динамически проверяет количество запросов.
Да, разобраться в этом не с первого раза — нормально
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4😁2
Если вы хотите использовать Minimal APIs в более вертикально-срезовой (vertical slice) структуре, вот простая абстракция:
- интерфейс IEndpoint для определения эндпоинтов
- несколько методов-расширений для автоматической регистрации эндпоинтов
Цена на старте? Пара миллисекунд.
👉 @KodBlog
- интерфейс IEndpoint для определения эндпоинтов
- несколько методов-расширений для автоматической регистрации эндпоинтов
Цена на старте? Пара миллисекунд.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2
Стоит ли Microsoft прекратить поддержку .NET Framework в Microsoft.Data.Sqlite в предстоящем релизе 11.0?
Обсуждение этого вопроса уже закрыто на GitHub, но Microsoft запрашивала мнение сообщества. (судя по скрину, комьюнити не против)
Проблема поддержки .NET Framework в GitHub SqLite: https://github.com/dotnet/efcore/issues/37895
👉 @KodBlog
Обсуждение этого вопроса уже закрыто на GitHub, но Microsoft запрашивала мнение сообщества. (судя по скрину, комьюнити не против)
Проблема поддержки .NET Framework в GitHub SqLite: https://github.com/dotnet/efcore/issues/37895
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
Не отправляйте несколько SQL-команд в базу данных (PostgreSQL) последовательно.
Вместо этого делайте так👇
Когда у вас есть кейс, где вы добавляете новую запись и затем читаете её, обычно выполняются два SQL-запроса: INSERT и SELECT.
С точки зрения выполнения это нормально, но что насчёт таких факторов, как:
1/ сетевая задержка (network latency)
2/ количество round-trip’ов к базе данных
Это ведь легко может снизить производительность, верно?
К счастью, с Npgsql это не обязательно.
У этого провайдера есть фича под названием batching.
Batching — это отправка нескольких SQL-команд в PostgreSQL за один round-trip к базе данных, вместо того чтобы вызывать Execute отдельно для каждой команды.
В документации Npgsql это описано через использование NpgsqlBatch, который упаковывает несколько NpgsqlBatchCommand в один запрос к серверу.
Важная деталь: если вы не начали собственную транзакцию, Npgsql автоматически оборачивает batch в неявную транзакцию.
Если один из запросов падает, остальные не выполняются, а весь batch откатывается (rollback).
👉 @KodBlog
Вместо этого делайте так
Когда у вас есть кейс, где вы добавляете новую запись и затем читаете её, обычно выполняются два SQL-запроса: INSERT и SELECT.
С точки зрения выполнения это нормально, но что насчёт таких факторов, как:
1/ сетевая задержка (network latency)
2/ количество round-trip’ов к базе данных
Это ведь легко может снизить производительность, верно?
К счастью, с Npgsql это не обязательно.
У этого провайдера есть фича под названием batching.
Batching — это отправка нескольких SQL-команд в PostgreSQL за один round-trip к базе данных, вместо того чтобы вызывать Execute отдельно для каждой команды.
В документации Npgsql это описано через использование NpgsqlBatch, который упаковывает несколько NpgsqlBatchCommand в один запрос к серверу.
Важная деталь: если вы не начали собственную транзакцию, Npgsql автоматически оборачивает batch в неявную транзакцию.
Если один из запросов падает, остальные не выполняются, а весь batch откатывается (rollback).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🍌2🔥1
В чем смысл System.Collections.Frozen по сравнению с System.Collections.Immutable?
Immutable-коллекции являются «неизменяемыми» в том смысле, что конкретный экземпляр коллекции нельзя изменить. Однако они поощряют мутации: не изменение самого экземпляра, а создание новых экземпляров на основе исходного. Поэтому у immutable-коллекций есть методы вроде Add и Remove, которые не изменяют исходный экземпляр, а вместо этого создают новый экземпляр, содержащий это изменение (в литературе такие коллекции часто называют «персистентными коллекциями»). В результате, помимо API, ориентированного на такие операции, реализации оптимизированы под подобные сценарии, в частности — под шаринг памяти между экземплярами.
Например, если у вас есть ImmutableDictionary<string, string>, то под капотом это древовидная структура данных, и при вызове Add создаётся новый ImmutableDictionary<string, string>, который шарит максимально возможную часть исходного дерева, добавляя только необходимые узлы для нового элемента. Это означает, что хотя ImmutableDictionary и «неизменяемый», он на самом деле не оптимизирован для быстрого чтения, например, TryGetValue — это операция O(log n).
С другой стороны, новые FrozenSet<> / FrozenDictionary<> действительно неизменяемые: у них нет API, который позволял бы или поощрял добавления, удаления и т.д. Они спроектированы только под те операции, которые вы с ними выполняете — чтение. Если вам не нужны API для каких-либо мутаций, можно просто использовать FrozenSet / FrozenDictionary.
Если вы планируете использовать их долго и готовы потратить больше времени на этапе построения, чтобы привести данные к форме, которая делает их быстрее для всех последующих чтений, можно передать optimizeForReading: true в соответствующие методы, и фабрика потратит больше времени на вычисление оптимального представления, чтобы последующие операции вроде TryGetValue выполнялись очень быстро. При этом не нужно думать о хранении данных таким образом, чтобы удешевить создание производных коллекций, так как API для подобных операций просто отсутствует.
👉 @KodBlog
Immutable-коллекции являются «неизменяемыми» в том смысле, что конкретный экземпляр коллекции нельзя изменить. Однако они поощряют мутации: не изменение самого экземпляра, а создание новых экземпляров на основе исходного. Поэтому у immutable-коллекций есть методы вроде Add и Remove, которые не изменяют исходный экземпляр, а вместо этого создают новый экземпляр, содержащий это изменение (в литературе такие коллекции часто называют «персистентными коллекциями»). В результате, помимо API, ориентированного на такие операции, реализации оптимизированы под подобные сценарии, в частности — под шаринг памяти между экземплярами.
Например, если у вас есть ImmutableDictionary<string, string>, то под капотом это древовидная структура данных, и при вызове Add создаётся новый ImmutableDictionary<string, string>, который шарит максимально возможную часть исходного дерева, добавляя только необходимые узлы для нового элемента. Это означает, что хотя ImmutableDictionary и «неизменяемый», он на самом деле не оптимизирован для быстрого чтения, например, TryGetValue — это операция O(log n).
С другой стороны, новые FrozenSet<> / FrozenDictionary<> действительно неизменяемые: у них нет API, который позволял бы или поощрял добавления, удаления и т.д. Они спроектированы только под те операции, которые вы с ними выполняете — чтение. Если вам не нужны API для каких-либо мутаций, можно просто использовать FrozenSet / FrozenDictionary.
Если вы планируете использовать их долго и готовы потратить больше времени на этапе построения, чтобы привести данные к форме, которая делает их быстрее для всех последующих чтений, можно передать optimizeForReading: true в соответствующие методы, и фабрика потратит больше времени на вычисление оптимального представления, чтобы последующие операции вроде TryGetValue выполнялись очень быстро. При этом не нужно думать о хранении данных таким образом, чтобы удешевить создание производных коллекций, так как API для подобных операций просто отсутствует.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍌6👎4🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Изучайте алгоритмы — наглядно
Отличная коллекция интерактивных алгоритмов, удобно разбитых по категориям. Рекомендуется посмотреть:
https://algorithm-visualizer.org
👉 @KodBlog
Отличная коллекция интерактивных алгоритмов, удобно разбитых по категориям. Рекомендуется посмотреть:
https://algorithm-visualizer.org
Please open Telegram to view this post
VIEW IN TELEGRAM
👏4❤3
Вот хороший пример использования перехватчиков (interceptors) в EF: отслеживание того, когда ваши сущности были созданы или изменены.
Вы можете использовать ChangeTracker, чтобы проверить состояние сущности и установить соответствующие поля.
Если вы всегда используете этот DbContext в рамках HTTP-запроса, вы даже можете передавать UserId.
Вы можете использовать ChangeTracker, чтобы проверить состояние сущности и установить соответствующие поля.
Если вы всегда используете этот DbContext в рамках HTTP-запроса, вы даже можете передавать UserId.
👍4👏2
Обработка «сырого» исключения базы данных при нарушении уникального ограничения приводит к появлению некрасивого
Библиотека EntityFramework.Exceptions решает эту проблему.
https://github.com/Giorgi/EntityFramework.Exceptions
👉 @KodBlog
DbUpdateException с вложенным provider-specific исключением, которое приходится по-разному парсить для SQL Server, PostgreSQL и SQLite.Библиотека EntityFramework.Exceptions решает эту проблему.
https://github.com/Giorgi/EntityFramework.Exceptions
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - Giorgi/EntityFramework.Exceptions: Strongly typed exceptions for Entity Framework Core. Supports SQLServer, PostgreSQL…
Strongly typed exceptions for Entity Framework Core. Supports SQLServer, PostgreSQL, SQLite, Oracle and MySql. - Giorgi/EntityFramework.Exceptions
😁1
16 полезных сайтов, которые сделают тебя лучшим разработчиком:
1. roadmap.sh — дорожные карты для изучения dev-ролей
2. explainshell.com — объясняет каждый флаг в bash-командах
3. regex101.com — тестирование и отладка регулярных выражений с live-обратной связью
4. jsoncrack.com — превращает сырой JSON в визуальную диаграмму
5. bundlephobia.com — показывает размер npm-пакета до установки
6. transform.tools — мгновенно конвертирует между форматами для разработки
7. webhook.site — live URL для логирования webhook-запросов
8. devhints.io — шпаргалки по языкам и инструментам
9. httpie.io/app — браузерный HTTP-клиент для работы с API
10. caniuse.com — проверка поддержки CSS и JS в браузерах
11. squoosh.app — сжатие изображений прямо в браузере
12. carbon.now.sh — превращает код в аккуратные скриншоты
13. overapi.com — одностраничные шпаргалки по разным темам
14. shortcuts.design — горячие клавиши для популярных dev-инструментов
15. tinywow.com — бесплатный конвертер файлов
16. getfluently.app — прокачка разговорного английского с помощью AI
👉 @KodBlog
1. roadmap.sh — дорожные карты для изучения dev-ролей
2. explainshell.com — объясняет каждый флаг в bash-командах
3. regex101.com — тестирование и отладка регулярных выражений с live-обратной связью
4. jsoncrack.com — превращает сырой JSON в визуальную диаграмму
5. bundlephobia.com — показывает размер npm-пакета до установки
6. transform.tools — мгновенно конвертирует между форматами для разработки
7. webhook.site — live URL для логирования webhook-запросов
8. devhints.io — шпаргалки по языкам и инструментам
9. httpie.io/app — браузерный HTTP-клиент для работы с API
10. caniuse.com — проверка поддержки CSS и JS в браузерах
11. squoosh.app — сжатие изображений прямо в браузере
12. carbon.now.sh — превращает код в аккуратные скриншоты
13. overapi.com — одностраничные шпаргалки по разным темам
14. shortcuts.design — горячие клавиши для популярных dev-инструментов
15. tinywow.com — бесплатный конвертер файлов
16. getfluently.app — прокачка разговорного английского с помощью AI
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤3👍3🍌1
CA1507: Используйте
У кого включено это правило анализа кода?
👉 @KodBlog
nameof вместо строкового литералаУ кого включено это правило анализа кода?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16👏1🍌1
Инжект настроек в .NET
У тебя есть 3 основных интерфейса на выбор. Но если выбрать не тот — приложение может просто игнорировать изменения конфигурации.
Вот простое объяснение:
1️⃣ IOptions
• Считывается один раз при старте приложения
• Кэшируется на весь жизненный цикл
• Подходит для статичных настроек, которые не меняются
2️⃣ IOptionsSnapshot
• Пересчитывается на каждый запрос
• Подхватывает изменения в
• Идеален для web API (Scoped lifetime)
3️⃣ IOptionsMonitor
• Обновляется в реальном времени
• Триггерит событие при изменении настроек
• Подходит для фоновых сервисов (Singleton lifetime)
Правило большого пальца (Rule of Thumb):
Используй
Переходи на
Используй
👉 @KodBlog
У тебя есть 3 основных интерфейса на выбор. Но если выбрать не тот — приложение может просто игнорировать изменения конфигурации.
Вот простое объяснение:
• Считывается один раз при старте приложения
• Кэшируется на весь жизненный цикл
• Подходит для статичных настроек, которые не меняются
• Пересчитывается на каждый запрос
• Подхватывает изменения в
appsettings.json без перезапуска• Идеален для web API (Scoped lifetime)
• Обновляется в реальном времени
• Триггерит событие при изменении настроек
• Подходит для фоновых сервисов (Singleton lifetime)
Правило большого пальца (Rule of Thumb):
Используй
IOptions для статической конфигурации.Переходи на
IOptionsSnapshot в веб-приложениях.Используй
IOptionsMonitor, когда нужны уведомления об изменениях в background-задачах.Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🍌2
Мой любимый способ конфигурировать Serilog — через настройки приложения.
Можно настраивать уровни логирования, внешние sinks, enrichers и многое другое.
Это также значит, что конфигурацию Serilog можно менять без изменений в коде.
👉 @KodBlog
Можно настраивать уровни логирования, внешние sinks, enrichers и многое другое.
Это также значит, что конфигурацию Serilog можно менять без изменений в коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👏1
Большинство .NET-разработчиков реализуют кэширование сложным способом.
Они пишут шаблонный (boilerplate) код в каждом методе сервиса — проверяют кэш, делают запрос к базе, сохраняют результат, обрабатывают время жизни.
Есть способ лучше, который почти не требует изменений в коде.
Он называется
И работает он совершенно иначе, чем
Ключевое отличие:
-
-
При наличии кэша не вызываются ни обработчик endpoint’а, ни запрос к базе, ни бизнес-логика.
Что делает
- Добавление кэширования одним атрибутом — без boilerplate-кода в сервисах
- Встроенный cache lock предотвращает проблему «thundering herd»
- Именованные политики задают поведение кэша централизованно
- Инвалидация по тегам позволяет сбрасывать группы связанных записей одним вызовом
- Опции
Но вот где большинство разработчиков ошибается:
Кэшируют ответы авторизованных API без разделения по пользователям
→ Данные пользователя A могут быть отданы пользователю B
→ Это реальная уязвимость безопасности
Читать гайд
👉 @KodBlog
Они пишут шаблонный (boilerplate) код в каждом методе сервиса — проверяют кэш, делают запрос к базе, сохраняют результат, обрабатывают время жизни.
Есть способ лучше, который почти не требует изменений в коде.
Он называется
Output Cache middleware в ASP.NET Core.И работает он совершенно иначе, чем
IMemoryCache или IDistributedCache.Ключевое отличие:
-
IMemoryCache и IDistributedCache кэшируют объекты внутри кода приложения-
Output Cache перехватывает HTTP-ответ на уровне middleware, сохраняет его целиком и отдает повторноПри наличии кэша не вызываются ни обработчик endpoint’а, ни запрос к базе, ни бизнес-логика.
Что делает
Output Cache мощным:- Добавление кэширования одним атрибутом — без boilerplate-кода в сервисах
- Встроенный cache lock предотвращает проблему «thundering herd»
- Именованные политики задают поведение кэша централизованно
- Инвалидация по тегам позволяет сбрасывать группы связанных записей одним вызовом
- Опции
VaryBy позволяют кэшировать отдельные ответы по заголовкам, query string, route-параметрам или кастомной логикеНо вот где большинство разработчиков ошибается:
Кэшируют ответы авторизованных API без разделения по пользователям
→ Данные пользователя A могут быть отданы пользователю B
→ Это реальная уязвимость безопасности
Читать гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8😁2