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

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

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
Алгоритм ограничения запросов: Sliding Window Counter

Этот алгоритм — комбинация 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 секунд, которая «плавает» поверх фиксированных окон и динамически проверяет количество запросов.

Да, разобраться в этом не с первого раза — нормально 🙂

👉 @KodBlog
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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52
Стоит ли Microsoft прекратить поддержку .NET Framework в Microsoft.Data.Sqlite в предстоящем релизе 11.0?

Обсуждение этого вопроса уже закрыто на GitHub, но Microsoft запрашивала мнение сообщества. (судя по скрину, комьюнити не против)

Проблема поддержки .NET Framework в GitHub SqLite: https://github.com/dotnet/efcore/issues/37895

👉 @KodBlog
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
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
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
Please open Telegram to view this post
VIEW IN TELEGRAM
👏43
Вот хороший пример использования перехватчиков (interceptors) в EF: отслеживание того, когда ваши сущности были созданы или изменены.

Вы можете использовать ChangeTracker, чтобы проверить состояние сущности и установить соответствующие поля.

Если вы всегда используете этот DbContext в рамках HTTP-запроса, вы даже можете передавать UserId.
👍4👏2
Обработка «сырого» исключения базы данных при нарушении уникального ограничения приводит к появлению некрасивого DbUpdateException с вложенным provider-specific исключением, которое приходится по-разному парсить для SQL Server, PostgreSQL и SQLite.

Библиотека EntityFramework.Exceptions решает эту проблему.

https://github.com/Giorgi/EntityFramework.Exceptions

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
😁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
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥73👍3🍌1
CA1507: Используйте nameof вместо строкового литерала

У кого включено это правило анализа кода?

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16👏1🍌1
Инжект настроек в .NET

У тебя есть 3 основных интерфейса на выбор. Но если выбрать не тот — приложение может просто игнорировать изменения конфигурации.

Вот простое объяснение:

1️⃣ IOptions
• Считывается один раз при старте приложения
• Кэшируется на весь жизненный цикл
• Подходит для статичных настроек, которые не меняются

2️⃣ IOptionsSnapshot
• Пересчитывается на каждый запрос
• Подхватывает изменения в appsettings.json без перезапуска
• Идеален для web API (Scoped lifetime)

3️⃣ IOptionsMonitor
• Обновляется в реальном времени
• Триггерит событие при изменении настроек
• Подходит для фоновых сервисов (Singleton lifetime)

Правило большого пальца (Rule of Thumb):
Используй IOptions для статической конфигурации.
Переходи на IOptionsSnapshot в веб-приложениях.
Используй IOptionsMonitor, когда нужны уведомления об изменениях в background-задачах.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10🍌2
Мой любимый способ конфигурировать Serilog — через настройки приложения.

Можно настраивать уровни логирования, внешние sinks, enrichers и многое другое.

Это также значит, что конфигурацию Serilog можно менять без изменений в коде.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👏1
Большинство .NET-разработчиков реализуют кэширование сложным способом.

Они пишут шаблонный (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
→ Это реальная уязвимость безопасности

Читать гайд

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
8😁2
Ищешь альтернативу Postman?
Apidog — это all-in-one инструмент для работы с API.

✓ Проектируй и управляй спецификациями API
✓ Мокай и тестируй endpoints в одном месте
✓ Генерируй документацию автоматически
✓ Тестируй интеграции с ИИ, такие как ChatGPT

Доступен в веб-версии и приложении с бесплатным тарифом:

http://midu.link/apidog

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
4😁4
Что такое breaking change для API?

Вот несколько примеров:

- Удаление или переименование API или параметров API
- Изменение поведения существующих API
- Изменение кодов ошибок API

Breaking change означает, что вам нужно версионировать API — иначе вы рискуете сломать существующих клиентов.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6😁1
Отличные ресурсы по системному дизайну
http://github.com/ashishps1/awesome-system-design-resources

Что внутри:

1. Базовые концепции — теорема CAP, консистентное хеширование, масштабируемость, доступность
2. Основы сетей — DNS, балансировка нагрузки, модель OSI, WebSockets
3. Глубокое погружение в базы данных — шардирование, репликация, SQL vs NoSQL
4. Разборы реальных систем — Twitter, Netflix, Uber, Google Drive
5. Включены диаграммы и примеры реализации кода

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
3🍌2
Большинство .NET-разработчиков используют AsNoTracking() время от времени — когда вспоминают.

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

Вот полная картина query tracking в EF Core, которую редко объясняют в одном месте.

Три метода. Одна цель: не трекать то, что вы не собираетесь менять.

AsNoTracking()

Самый быстрый вариант. Полностью обходит change tracker.

Идеален для любых read-only запросов — списки, результаты поиска, отчёты, фоновые задачи.

Есть один нюанс: если одна и та же сущность появляется через разные join’ы, EF Core создаст два разных C#-объекта в памяти вместо одного.

Это может незаметно ломать поведение.

AsNoTrackingWithIdentityResolution()

Даёт тот же плюс отсутствия трекинга, но решает проблему дубликатов объектов.

EF Core по-прежнему не использует change tracker, но поддерживает identity map, благодаря чему одна и та же сущность всегда соответствует одному и тому же C#-объекту.

Немного медленнее, чем чистый AsNoTracking, но правильный выбор для сложных запросов с Include.

UseQueryTrackingBehavior()

Перестаньте писать AsNoTracking в каждом запросе.

Задайте это глобально в DbContext при старте приложения.

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

А там, где нужно изменение данных, явно используйте AsTracking().

Используйте NoTracking, когда:

→ read-only API endpoint’ы
→ пагинация и списки
→ отчёты и экспорт данных
→ чтение данных в фоновых задачах
→ страницы с результатами поиска

Оставляйте tracking, когда:

→ загружаете сущность для последующего обновления
→ после запроса вызывается SaveChanges
→ мутируете сложные графы объектов
→ работаете с disconnected-сценариями сущностей

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
12🔥3😁1
DelegatingHandlers позволяют добавлять поведение до или после выполнения запросов через HttpClient.

Это как middleware, но для исходящих (outgoing) запросов.

Отличный кейс использования этой возможности?

Добавление заголовков аутентификации к запросу. 👇

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👀2
Однажды я заплатил $40 за .NET-приложение с самописным ORM.

В нём были SQL-инъекции, сломанные транзакции и ноль тестов.

Вот 6 ORM-репозиториев, которые действительно стоят внимания:

1. Entity Framework Core - https://github.com/dotnet/efcore
2. Dapper - https://github.com/DapperLib/Dapper
3. NHibernate - https://github.com/nhibernate/nhibernate-core
4. linq2db - https://github.com/linq2db/linq2db
5. Marten - https://github.com/JasperFx/marten
6. SqlKata - https://github.com/sqlkata/querybuilder

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
4😁2👍1
Этот динамический парсинг JSON уже не раз меня подводил — я обычно кастую к string через as string, где это возможно.

В JSON.NET (JObject / JValue) значения ведут себя как dynamic при цепочках обращений, но при этом не кастуются, потому что по сути это Expando-подобные объекты.

Не первый раз на это натыкаюсь, и, скорее всего, не последний 😂

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤩1🍾1