Rate limiting в ASP.NET Core — один из уровней защиты API
Ограничение частоты запросов помогает сдерживать перебор паролей, злоупотребления API и перегрузку ресурсов. Но одного middleware недостаточно.
Защищайте весь путь запроса:
CDN и защита от DDoS → WAF → API Gateway → .NET API → зависимые сервисы
На внешних уровнях фильтруйте вредоносный трафик, в API задавайте лимиты для пользователей и операций, а обращения к зависимостям ограничивайте по частоте и числу одновременных запросов.
👉 @KodBlog
Ограничение частоты запросов помогает сдерживать перебор паролей, злоупотребления API и перегрузку ресурсов. Но одного middleware недостаточно.
Защищайте весь путь запроса:
CDN и защита от DDoS → WAF → API Gateway → .NET API → зависимые сервисы
На внешних уровнях фильтруйте вредоносный трафик, в API задавайте лимиты для пользователей и операций, а обращения к зависимостям ограничивайте по частоте и числу одновременных запросов.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾2
Маленькие сервисы не гарантируют быстрое оформление заказа
Если checkout последовательно вызывает три сервиса, пользователь ждёт ответа каждого. Каждый вызов добавляет задержку и ещё одну точку возможного отказа.
Прежде чем добавлять серверы, проследите весь путь запроса. Какие данные нужны прямо сейчас? Где повторяются чтения? Какие действия можно выполнить позже?
Затем проверьте границы сервисов. Если двум сервисам почти для каждой задачи нужны данные друг друга, общение по HTTP не уменьшит их связанность. Возможно, эту логику стоит оставить в одном модуле.
Небольшой сервис полезен, когда способен выполнять свою задачу без постоянной помощи соседей.
Пять вопросов перед разделением системы
👉 @KodBlog
Если checkout последовательно вызывает три сервиса, пользователь ждёт ответа каждого. Каждый вызов добавляет задержку и ещё одну точку возможного отказа.
Прежде чем добавлять серверы, проследите весь путь запроса. Какие данные нужны прямо сейчас? Где повторяются чтения? Какие действия можно выполнить позже?
Затем проверьте границы сервисов. Если двум сервисам почти для каждой задачи нужны данные друг друга, общение по HTTP не уменьшит их связанность. Возможно, эту логику стоит оставить в одном модуле.
Небольшой сервис полезен, когда способен выполнять свою задачу без постоянной помощи соседей.
Пять вопросов перед разделением системы
Please open Telegram to view this post
VIEW IN TELEGRAM
💯2🍾2❤1
Долгий отчёт не должен удерживать HTTP-запрос открытым
Сохраните задание и верните
На старте обработчик может работать внутри приложения, разделяя с API процессор и память. Когда тяжёлые задания начинают замедлять обычные запросы, вынесите его в отдельный процесс и передавайте задания через очередь. Тогда число обработчиков можно увеличивать независимо от API.
Отслеживайте время ожидания в очереди, обрабатывайте сбои и обеспечивайте безопасные повторные попытки. Очередь сглаживает всплески нагрузки, но не решает постоянную нехватку вычислительных ресурсов.
Пошаговый разбор и цена каждого решения
👉 @KodBlog
Сохраните задание и верните
202 Accepted с его идентификатором. Фоновый обработчик выполнит работу, а пользователь сможет проверять прогресс.На старте обработчик может работать внутри приложения, разделяя с API процессор и память. Когда тяжёлые задания начинают замедлять обычные запросы, вынесите его в отдельный процесс и передавайте задания через очередь. Тогда число обработчиков можно увеличивать независимо от API.
Отслеживайте время ожидания в очереди, обрабатывайте сбои и обеспечивайте безопасные повторные попытки. Очередь сглаживает всплески нагрузки, но не решает постоянную нехватку вычислительных ресурсов.
Пошаговый разбор и цена каждого решения
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🍾1
Вышел .NET 11 RC2
Microsoft представила второй релиз-кандидат .NET 11. Это ещё не финальная версия, но сборка уже имеет поддержку go-live для использования в production.
Что нового:
• Настройка начального параллелизма HTTP/2.
• Ускорение обработки файловых масок в MSBuild.
Настройка минимального возраста NuGet-пакетов через CLI.
API виртуализации
Официальный анонс и полный список изменений
👉 @KodBlog
Microsoft представила второй релиз-кандидат .NET 11. Это ещё не финальная версия, но сборка уже имеет поддержку go-live для использования в production.
Что нового:
• Настройка начального параллелизма HTTP/2.
• Ускорение обработки файловых масок в MSBuild.
Настройка минимального возраста NuGet-пакетов через CLI.
API виртуализации
QuickGrid вышли из экспериментального статуса.Официальный анонс и полный список изменений
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾1
Коварные баги в .NET не выбрасывают исключений.
Регистрируете сервис как
Не захватывайте scoped-зависимость внутри singleton. Для работы с БД создавайте отдельную область через
Сталкивались с такой ошибкой?
👉 @KodBlog
Регистрируете сервис как
Singleton и внедряете в него DbContext, который по умолчанию имеет lifetime Scoped. Без проверки областей видимости приложение может запуститься, но запросы начнут использовать один контекст: устаревшие данные, накопление отслеживаемых сущностей и ошибки при параллельной работе.Не захватывайте scoped-зависимость внутри singleton. Для работы с БД создавайте отдельную область через
IServiceScopeFactory или контекст через IDbContextFactory<TContext>.Сталкивались с такой ошибкой?
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🍾1
Оплата прошла. Заказ не оформился.
Так бывает, когда оплатой и остатками управляют разные сервисы. Успешное списание денег ещё не означает, что товар зарезервирован.
Этот сценарий нужно учитывать заранее: сохранять результаты шагов и понимать, что делать дальше. Если товар закончился, может потребоваться возврат денег.
Saga координирует процесс между сервисами. Каждый шаг выполняется в своей локальной транзакции. Если следующий шаг завершается ошибкой, компенсирующее действие отменяет эффект предыдущего: например, возвращает оплату.
Но возврат тоже может не пройти. Сохраняйте его статус, обеспечивайте безопасные повторные попытки и отмечайте случаи, требующие ручного вмешательства. «Запрос на возврат отправлен» не означает «деньги возвращены».
Реализация саги заказа с MassTransit
👉 @KodBlog
Так бывает, когда оплатой и остатками управляют разные сервисы. Успешное списание денег ещё не означает, что товар зарезервирован.
Этот сценарий нужно учитывать заранее: сохранять результаты шагов и понимать, что делать дальше. Если товар закончился, может потребоваться возврат денег.
Saga координирует процесс между сервисами. Каждый шаг выполняется в своей локальной транзакции. Если следующий шаг завершается ошибкой, компенсирующее действие отменяет эффект предыдущего: например, возвращает оплату.
Но возврат тоже может не пройти. Сохраняйте его статус, обеспечивайте безопасные повторные попытки и отмечайте случаи, требующие ручного вмешательства. «Запрос на возврат отправлен» не означает «деньги возвращены».
Реализация саги заказа с MassTransit
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🍾1
Практические уроки для Backend, Data Engineering и DevOps
Площадка с пошаговыми туториалами и облачными окружениями. Изучаем теорию и сразу выполняем команды без настройки локальной среды. В каталоге PostgreSQL, Redis, Docker, Kubernetes, Airflow, Spark и ClickHouse.
https://prepare.sh/
👉 @KodBlog
Площадка с пошаговыми туториалами и облачными окружениями. Изучаем теорию и сразу выполняем команды без настройки локальной среды. В каталоге PostgreSQL, Redis, Docker, Kubernetes, Airflow, Spark и ClickHouse.
https://prepare.sh/
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🍾1
Данные изменились. Другой сервер всё ещё показывает старое значение.
Так бывает, когда каждый экземпляр приложения хранит локальный кэш. Удаление ключа на сервере A не очищает его копию на сервере B.
Перед кэшированием определите, как долго данные могут оставаться устаревшими. Старое имя в профиле ненадолго допустимо. Отозванное право доступа требует более строгих правил.
Можно рассылать уведомления об изменениях, чтобы серверы удаляли свои копии. Но сообщения могут теряться. Поэтому задавайте абсолютный срок жизни записи: пропущенное уведомление не должно оставлять старое значение в кэше навсегда.
Если операция требует актуальных данных, проверяйте их в системе, которая ими управляет.
Разбор проблемы локального кэша и Redis backplane
👉 @KodBlog
Так бывает, когда каждый экземпляр приложения хранит локальный кэш. Удаление ключа на сервере A не очищает его копию на сервере B.
Перед кэшированием определите, как долго данные могут оставаться устаревшими. Старое имя в профиле ненадолго допустимо. Отозванное право доступа требует более строгих правил.
Можно рассылать уведомления об изменениях, чтобы серверы удаляли свои копии. Но сообщения могут теряться. Поэтому задавайте абсолютный срок жизни записи: пропущенное уведомление не должно оставлять старое значение в кэше навсегда.
Если операция требует актуальных данных, проверяйте их в системе, которая ими управляет.
Разбор проблемы локального кэша и Redis backplane
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2❤1
Как выбрать первый модуль для выделения в отдельный сервис
Начните с модуля, у которого мало связей с остальным приложением. Он должен отвечать за понятную задачу, владеть своими данными и иметь причину для отдельного запуска — например, потребность в независимом масштабировании.
До переноса кода найдите все места, которые напрямую читают или изменяют его таблицы. Замените такие обращения явным контрактом взаимодействия и продумайте миграцию данных.
Часть локальных вызовов станет сетевой. Понадобятся тайм-ауты, обработка сбоев и распределённая трассировка, чтобы отслеживать запрос между приложениями.
Выделите один модуль, проверьте его в работе и учтите полученный опыт, прежде чем браться за следующий.
Руководство по выделению первого сервиса и переносу данных
👉 @KodBlog
Начните с модуля, у которого мало связей с остальным приложением. Он должен отвечать за понятную задачу, владеть своими данными и иметь причину для отдельного запуска — например, потребность в независимом масштабировании.
До переноса кода найдите все места, которые напрямую читают или изменяют его таблицы. Замените такие обращения явным контрактом взаимодействия и продумайте миграцию данных.
Часть локальных вызовов станет сетевой. Понадобятся тайм-ауты, обработка сбоев и распределённая трассировка, чтобы отслеживать запрос между приложениями.
Выделите один модуль, проверьте его в работе и учтите полученный опыт, прежде чем браться за следующий.
Руководство по выделению первого сервиса и переносу данных
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🍾1
12 библиотек .NET, о которых стоит знать каждому разработчику
Сохраняйте подборку и делитесь с коллегами🔖
👉 @KodBlog
Сохраняйте подборку и делитесь с коллегами
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥5🍾1
Заказ сохранился, но так и не отправился
Приложение записывает заказ в БД, затем публикует событие для запуска доставки. Если брокер недоступен, а приложение остановится до повторной попытки, событие может потеряться.
Transactional Outbox помогает пережить такой сбой. Заказ и событие сохраняются в одной транзакции БД: либо фиксируются обе записи, либо ни одна.
Фоновый обработчик читает таблицу outbox и отправляет события брокеру. Если отправка не удалась, запись остаётся для повторной попытки.
Но есть нюанс: обработчик может отправить событие и упасть до того, как отметит его отправленным. После перезапуска сообщение уйдёт повторно.
Поэтому получатель должен обрабатывать дубликаты безопасно. Повторное сообщение не должно приводить к повторной отправке заказа.
Проверьте оба сценария:
• Остановите брокер перед отправкой события.
• Остановите обработчик после отправки, но до обновления записи в outbox.
Разбор механизма и настройки в EF Core
👉 @KodBlog
Приложение записывает заказ в БД, затем публикует событие для запуска доставки. Если брокер недоступен, а приложение остановится до повторной попытки, событие может потеряться.
Transactional Outbox помогает пережить такой сбой. Заказ и событие сохраняются в одной транзакции БД: либо фиксируются обе записи, либо ни одна.
Фоновый обработчик читает таблицу outbox и отправляет события брокеру. Если отправка не удалась, запись остаётся для повторной попытки.
Но есть нюанс: обработчик может отправить событие и упасть до того, как отметит его отправленным. После перезапуска сообщение уйдёт повторно.
Поэтому получатель должен обрабатывать дубликаты безопасно. Повторное сообщение не должно приводить к повторной отправке заказа.
Проверьте оба сценария:
• Остановите брокер перед отправкой события.
• Остановите обработчик после отправки, но до обновления записи в outbox.
Разбор механизма и настройки в EF Core
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🍾1
Если сохранять данные в БД и публиковать сообщение двумя отдельными шагами, сбой между ними может привести к потере сообщения.
Outbox решает эту проблему: данные и сообщение сохраняются в одной транзакции, а фоновый обработчик позже отправляет сообщение брокеру.
👉 @KodBlog
Outbox решает эту проблему: данные и сообщение сохраняются в одной транзакции, а фоновый обработчик позже отправляет сообщение брокеру.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾4❤2
Параллельное ожидание async-операций в .NET
Не ожидайте независимые асинхронные операции по очереди. Запустите их сразу, а затем дождитесь завершения через
👉 @KodBlog
Не ожидайте независимые асинхронные операции по очереди. Запустите их сразу, а затем дождитесь завершения через
Task.WhenAll() — общее время не будет складываться из времени каждой операции.Please open Telegram to view this post
VIEW IN TELEGRAM
🍾5
lock в C# не остановит второй экземпляр приложенияКогда приложение работает в нескольких экземплярах, каждый может запустить одну и ту же задачу по расписанию. У каждого процесса свой
lock в памяти.Для координации можно использовать advisory lock в PostgreSQL: оба экземпляра пытаются получить одну и ту же блокировку. Получивший запускает задачу, другой пропускает попытку.
Но есть нюансы:
• Сессионная блокировка удерживается соединением с БД. Если соединение потеряно, другой воркер может получить её, пока первый ещё выполняет работу.
• Блокировка не хранит историю выполненных запусков — их нужно учитывать отдельно.
• Повторное выполнение должно быть безопасным: блокировка сама по себе не гарантирует «ровно один раз».
Разбор и пример на C#
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾3
12 возможностей современного C#, которые стоит знать .NET-разработчику
C# заметно изменился: лаконичный синтаксис, средства работы с
Собрали 12 возможностей, которые пригодятся в повседневной разработке.
👉 @KodBlog
C# заметно изменился: лаконичный синтаксис, средства работы с
null, улучшения производительности и инструменты для конкурентного выполнения задач помогают писать более понятный и надёжный код.Собрали 12 возможностей, которые пригодятся в повседневной разработке.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2🍾1
Отдельная схема БД ещё не изолирует данные модуля
Если все модули используют одну учётную запись PostgreSQL, она может иметь доступ ко всем таблицам. Названия папок и схем этих прав не меняют.
Чтобы закрепить границы, каждому модулю можно выделить собственную роль с доступом только к его схеме и указать её в строке подключения. Тогда случайный запрос к приватной таблице другого модуля будет отклонён самой БД.
При этом каждому модулю по-прежнему нужны свой
Так границы модулей становятся проверяемым ограничением, а не просто договорённостью команды.
Практическое руководство: роли PostgreSQL, права доступа и настройка EF Core
👉 @KodBlog
Если все модули используют одну учётную запись PostgreSQL, она может иметь доступ ко всем таблицам. Названия папок и схем этих прав не меняют.
Чтобы закрепить границы, каждому модулю можно выделить собственную роль с доступом только к его схеме и указать её в строке подключения. Тогда случайный запрос к приватной таблице другого модуля будет отклонён самой БД.
При этом каждому модулю по-прежнему нужны свой
DbContext и явный контракт доступа к общим данным. Для совместного чтения владеющий модуль может предоставить API или представление (VIEW) с намеренно выданными правами.Так границы модулей становятся проверяемым ограничением, а не просто договорённостью команды.
Практическое руководство: роли PostgreSQL, права доступа и настройка EF Core
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1🍾1
Singleton, Scoped и Transient в ASP.NET Core
Время жизни сервиса влияет на потребление памяти, состояние приложения и безопасность работы с несколькими потоками.
Singleton — один экземпляр на всё время работы контейнера DI. Подходит для общей конфигурации и потокобезопасных кэшей. Изменяемое состояние требует синхронизации, а зависимости должны быть рассчитаны на длительное использование.
Scoped — один экземпляр на scope, обычно на HTTP-запрос. Подходит для EF Core
Transient — новый экземпляр при каждом получении из DI. Подходит для лёгких независимых сервисов. Частое создание добавляет расходы на выделение памяти и инициализацию. Если такой объект сохраняется в Singleton, он остаётся жить вместе с ним.
Частая ошибка — внедрить Scoped-сервис в Singleton. Это может привести к некорректному разделению состояния и конфликтам при одновременных обращениях. Проверка scope помогает обнаружить такую зависимость.
Для выполнения операции создавайте отдельный scope через
Для работы с БД внутри
👉 @KodBlog
Время жизни сервиса влияет на потребление памяти, состояние приложения и безопасность работы с несколькими потоками.
Singleton — один экземпляр на всё время работы контейнера DI. Подходит для общей конфигурации и потокобезопасных кэшей. Изменяемое состояние требует синхронизации, а зависимости должны быть рассчитаны на длительное использование.
Scoped — один экземпляр на scope, обычно на HTTP-запрос. Подходит для EF Core
DbContext и состояния запроса. В фоновых сервисах scope нужно создавать явно.Transient — новый экземпляр при каждом получении из DI. Подходит для лёгких независимых сервисов. Частое создание добавляет расходы на выделение памяти и инициализацию. Если такой объект сохраняется в Singleton, он остаётся жить вместе с ним.
Частая ошибка — внедрить Scoped-сервис в Singleton. Это может привести к некорректному разделению состояния и конфликтам при одновременных обращениях. Проверка scope помогает обнаружить такую зависимость.
Для выполнения операции создавайте отдельный scope через
IServiceScopeFactory:await using var scope = scopeFactory.CreateAsyncScope();
var service = scope.ServiceProvider
.GetRequiredService<IMyScopedService>();
await service.ProcessAsync();
Для работы с БД внутри
BackgroundService можно использовать такой scope или IDbContextFactory<TContext>:await using var db =
await dbContextFactory.CreateDbContextAsync();
var orders = await db.Orders.ToListAsync();
DbContext не потокобезопасен. Scoped определяет время жизни, но не защищает от конкурентного доступа. Для параллельных операций используйте отдельные экземпляры контекста.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🍾2
Два запроса — одна квартира — двойное бронирование
Оба запроса могут проверить доступность квартиры и увидеть свободные даты. Проблема возникает между проверкой и сохранением: за это время другой запрос успевает создать бронь.
Один из способов защиты — оптимистическая конкуренция через общую строку квартиры. При создании бронирования каждый запрос также обновляет эту строку в одной транзакции. У неё есть токен версии, который меняется при обновлении.
EF Core добавляет прочитанную версию в условие
После конфликта нельзя просто повторить запись. Нужно заново прочитать актуальные данные и проверить доступность дат.
Версия только на новой строке бронирования здесь не поможет: запросы создают разные строки и не конфликтуют между собой.
Разбор и пример на EF Core
👉 @KodBlog
Оба запроса могут проверить доступность квартиры и увидеть свободные даты. Проблема возникает между проверкой и сохранением: за это время другой запрос успевает создать бронь.
Один из способов защиты — оптимистическая конкуренция через общую строку квартиры. При создании бронирования каждый запрос также обновляет эту строку в одной транзакции. У неё есть токен версии, который меняется при обновлении.
EF Core добавляет прочитанную версию в условие
UPDATE. Первый запрос успешно сохраняет изменения. Второй использует уже устаревшую версию и получает DbUpdateConcurrencyException; его транзакция откатывается.После конфликта нельзя просто повторить запись. Нужно заново прочитать актуальные данные и проверить доступность дат.
Версия только на новой строке бронирования здесь не поможет: запросы создают разные строки и не конфликтуют между собой.
Разбор и пример на EF Core
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🍾1