C# Portal | Программирование
15K subscribers
753 photos
86 videos
19 files
665 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Связь: @devmangx

РКН: https://clck.ru/3FocB6
Download Telegram
Трудно отследить, что происходит внутри твоего .NET-приложения?

Вот базовая настройка OpenTelemetry, которую я использую в каждом проекте:

- ASP .NET Core instrumentation
- HttpClient instrumentation
- EF Core instrumentation
- Redis instrumentation
- Npgsql (или SqlClient)

Это даёт полноценные, сквозные трассировки — и всё это быстро.

Для визуализации можно использовать:

- Seq
- Jaeger
- Grafana
- Aspire Dashboard

Seq также поддерживает структурированные логи, что хорошо сочетается с трассировкой.

Вот практическое руководство: ссылка

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍2🔥2
Производительность критична для любого приложения.

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

В этом мы разберёмся на практике: как оптимизировать медленный реальный запрос на EF Core. EF Core предоставляет мощные инструменты, но при неправильном использовании может приводить к медленным запросам.

Автор покажет, как пошагово оптимизировал запрос на EF Core — с неприемлемых 30 секунд до сверхбыстрых 30 миллисекунд. 😮

В приложении используются следующие сущности:

🔸Users (Пользователи): каждый пользователь может иметь много постов и комментариев.
🔸Comments (Комментарии): каждый комментарий принадлежит пользователю и связан с постом.
🔸Categories (Категории): посты имеют категории.
🔸Posts (Посты): каждый пост относится к категории и может иметь множество лайков.
🔸Likes (Лайки): каждый лайк относится к посту.

Условие задачи:

Выбрать топ-5 пользователей, которые оставили наибольшее число комментариев за последние 7 дней под постами в категории ".NET".

Для каждого пользователя вернуть:

🔸UserId
🔸Username
🔸Количество комментариев пользователя (только по постам из категории ".NET" за последние 7 дней)
🔸Топ-3 поста в категории ".NET" с наибольшим числом лайков, под которыми этот пользователь чаще всего комментировал (PostId, LikesCount)

Полное разбор задачи по оптимизации EF Core-запроса — читай тут

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
6🔥4
Самая большая ошибка джуниоров? Игнорировать SQL.

Невозможно по-настоящему понять, как работают базы данных, если полагаться только на ORM.

Реляционные базы данных существуют уже более 40 лет и не просто так.

Сфокусируйся на:

🔸основах SQL
🔸моделировании данных
🔸транзакциях
🔸индексировании

Окупается быстро. Недавно я оптимизировал два запроса:

> SELECT: с 70 мс до 1 мс
> UPDATE: с 300 мс до 52 мс


Как именно — cмотрите тут

Освой SQL и ты вырастешь как разработчик в 10 раз быстрее 📖

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥21😁1
𝟰𝟱 вопросов для подготовки к собеседованию по ASP.NET Core

→ Объясните, как работает маршрутизация в ASP . NET Core
→ Что такое middleware и в каком порядке они выполняются?
→ Как можно остановить выполнение последующих middleware?
→ В чём разница между MVC и Razor Pages?
→ Назовите 3 способа создания middleware
→ Объясните, как работает многослойная конфигурация в appsettings.json
→ В чём разница между сервисами Singleton, Scoped и Transient?
→ Как использовать Scoped-сервис внутри Singleton-сервиса?
→ Как выполнить код при запуске и остановке приложения?
→ Что такое BackgroundService?
→ Назовите несколько способов чтения данных из конфигурации appsettings.json
→ Что такое Options Pattern?
→ Назовите случаи использования ISnapshotMonitor и IOptionsMonitor
→ Как валидировать конфигурацию?
→ В чём разница между DataAnnotations и FluentValidation?
→ Какие бывают атрибуты фильтров у контроллеров?
→ Почему Minimal API работают быстрее, чем контроллеры?
→ Как добавить авторизацию в проект?
→ Как добавить авторизацию ко всем методам контроллера, кроме одного?
→ Как бы вы реализовали функциональность входа в систему (Log-In)?
→ Объясните, как работают JWT-токены
→ Объясните Refresh-токены и как они работают
→ Как бы вы реализовали доступ к ресурсам на основе прав пользователя?
→ Для чего используется HostedService?
→ Объясните разницу между PeriodicTimer и await Task.Delay()
→ Что такое HSTS?
→ Как вернуть файл из API-эндпойнта?
→ Как принять файл через API-эндпойнт?
→ Как получить параметры query string в API-эндпойнте?
→ Как получить информацию о текущем авторизованном пользователе?
→ Как внедрять зависимости в Minimal API?
→ Как структурировать эндпойнты в Minimal API?
→ Что такое Output Caching?
→ В чём разница между IMemoryCache и IDistributedCache?
→ Объясните, как работает HybridCache или FusionCache
→ Какие паттерны кэширования вы знаете?
→ Для чего используется Rate Limiting и какие его типы существуют?
→ Как инвалидировать данные в OutputCache?
→ Как реализовать версионирование API?
→ Как добавить версионирование в существующий API, если нельзя менять URL?
→ Для чего используется Swagger?
→ Как задокументировать эндпойнты, модели и поля в Swagger?
→ Как получить строку подключения из конфигурации?
→ Как развернуть приложение ASP. NET Core?
→ Как настроить логирование в ASP. NET Core?


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22
Минималистичные API + версионирование API = дублирующийся беспорядок?

Нет, если сделать правильно.

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

Версию указываешь один раз — и она применяется ко всем endpoint'ам внутри группы. Чище маршруты, меньше дублирования.

Отлично работает и для префиксов вроде /v1

Хочешь увидеть, как это реализуется (и для Minimal API, и для контроллеров)?

▶️Вот гайд: ссылка

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
Что такое JSON Web Token (JWT)?

JWT — это компактный, безопасный для передачи по URL токен, предназначенный для безопасной передачи информации между двумя сторонами — обычно между клиентом и сервером.

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

JWT выглядит так: xxxxx.yyyyy.zzzzz

Он состоит из трёх частей:

🔸Header: указывает тип токена и алгоритм подписи (например, HMAC или RSA)
🔸Payload: содержит claims — данные о пользователе, такие как userId, role и т. д.
🔸Signature: используется для проверки подлинности отправителя и гарантирует, что токен не был изменён

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

1. Пользователь входит в систему, вводя логин и пароль.
2. Сервер проверяет учётные данные и генерирует JWT.
3. Сервер отправляет токен обратно клиенту.
4. Клиент сохраняет токен (обычно в localStorage или в cookie).
5. При последующих запросах клиент добавляет JWT в заголовок Authorization

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥42👏2🐳1
Одна из самых недооценённых возможностей HttpClient?

DelegatingHandler — это middleware для исходящих HTTP-запросов.

Идеально подходит для реализации сквозной логики, такой как:

➣ Аутентификация
➣ Логирование
➣ Аудит
➣ Кэширование
➣ Повторные попытки (Retries)

Вместо того чтобы дублировать этот код в каждом запросе — оформляется единый чистый pipeline.

Вот как использовать DelegatingHandler в .NET

А ты как обрабатываешь сквозную HTTP-логику в своих проектах? 📝

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍4
Исключения это Goto-команды современного .NET-разработчика. 😊
(И это не комплимент)

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

Но вот в чём проблема:

➣ Они ломают поток выполнения программы.
➣ Заставляют каждый вызывающий код оборачивать логику в try-catch (иначе — падение).
➣ И что хуже всего — при чрезмерном использовании могут влиять на производительность.

Что использовать вместо?

Паттерн Result


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

Плюсы:

Без неожиданностей
Без скрытых переходов
Предсказуемый, читаемый контроль потока

Совершенен ли этот подход? Нет.

Он может показаться многословным, и в C# пока нет нативной поддержки.

Но он даёт чёткость и явность в обработке ошибок.

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

Можно продолжать:

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

Или можно использовать Result pattern:

– проектировать поведение на случай ошибок заранее
– явно различать успех и неудачу

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤨97👍6
This media is not supported in your browser
VIEW IN TELEGRAM
Проект дня: переиспользуемый пайплайн деплоя, написанный на C#, который может взять любой проект на Aspire и задеплоить его на виртуальную машину через SSH и Docker.

➟ Использование C# >>>> shell-скрипты, вперемешку с YAML 🤮
➟ Код пайплайна работает поверх модели. Один и тот же код подходит для любого Aspire-приложения без изменений. Это динамический шаблон пайплайна.
➟ Может запускаться локально или в CI
➟ Построено на новых API, которые появятся в Aspire 9.4 (ты тоже можешь собрать свой пайплайн и задеплоить куда угодно!)

https://github.com/davidfowl/AspirePipelines

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
Тестировать API, не выходя из VS Code? Да, пожалуйста.

Новое расширение Postman для VS Code переносит разработку API прямо в IDE

Что оно умеет:

➣ Отправка HTTP-, WebSocket- и gRPC-запросов прямо из VS Code
➣ Совместное использование тестовых скриптов через коллекции Postman
➣ Импорт .env-файлов без ручного ввода переменных
➣ Отладка эндпоинтов рядом с кодом, в одном окне

Попробовать можно здесь:

🔸https://fnf.dev/44C6rRm

А вот ещё пара обновлений от Postman, которые стоит заценить:

Интеграция с Jira Cloud

Падаешь на 500-ке при вызове API?

Создавай баг-репорты в Jira за один клик — без переключения между тулзами:

➣ Быстрое создание задач из упавших запросов
➣ Автоматически прикладываются заголовки, токены, тело запроса и ответ
➣ Добавляются конфигурация окружения и шаги воспроизведения

👉 https://fnf.dev/3THdIZM

Интеграция с GitHub

Держи API-спеки и исходники в синхронизации:

➣ Автокоммит коллекций в репозиторий
➣ Просмотр изменений в API рядом с кодом в pull request
➣ Прогон тестов в CI на тех же коллекциях, с которыми работает команда

Подробнее: https://fnf.dev/4l2905d

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3
Использование nameof вместо ToString() при обращении к имени члена перечисления в .NET — это абсолютно валидная техника оптимизации производительности.

В этом нет ничего надуманного, даже ReSharper содержит инспекцию на этот случай. nameof выносит получение строки в compile-time, тем самым существенно снижает время выполнения и устраняет аллокации — что особенно важно в производительно-критичных hot-path'ах

Reddit тред -> ссылка

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍62🤔1🥴1
Вот как я получаю индекс каждого элемента в .NET 9

Используй метод Index из LINQ.

LINQ всегда был крайне полезным инструментом для .NET-разработчиков.

Но с выходом .NET 9 в LINQ появились три новых метода:

> Index
> CountBy
> AggregateBy

Сконцентрируемся на методе Index.

Метод Index возвращает перечисление (enumerable), в котором каждый элемент представлен в виде кортежа с его индексом.

Это отличный способ, если тебе нужно получить индекс каждого элемента в коллекции.

Пример кода прикрепил 😎

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥6
Как реализовать Refresh Tokens в ASP.NET Core и как отозвать токены пользователя 👇

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

Обычно JWT-аутентификация использует два токена:

● Access token — даёт доступ к защищённым ресурсам и живёт недолго (обычно 5–10 минут).
● Короткий срок жизни снижает риски при компрометации.

Refresh token — нужен для получения нового access token без повторного входа пользователя в систему.

Если access token живёт всего несколько минут — пользователь будет постоянно переавторизовываться. Это ужасный UX.

Здесь и вступает в игру refresh token. Он позволяет «тихо» получить новый access token, когда текущий истёк, не требуя логина.

Refresh token, как правило, живёт дольше — от нескольких дней до недель.

Anton Martyniuk рассказал:

🔸Что такое refresh токены и как они работают
🔸Как реализовать их в ASP.NET Core
🔸Как обеспечить безопасность и соблюдать best practices
🔸Как отзывать refresh токены, чтобы динамически обновлять права доступа пользователя

Хочешь прокачать безопасность в ASP.NET Core по индустриальным стандартам? вот статья

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍3👀2
GitHub Copilot Chat теперь с открытым кодом

Microsoft сделали первый шаг к превращению VS Code в полноценный опенсорс AI-редактор

Теперь можно заглянуть под капот: как работает agent mode, что уходит в LLM, как устроены промпты и даже какую телеметрию они собирают

Код доступен на GitHub ✌️

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
7🔥4
C#‑«скрипт» для отправки HTTP-запроса с использованием Flurl.

Эта возможность появится в .NET 10 — подробнее

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍124🤔3😁1
Как быстро расчистить раздутые API-контроллеры:

Используй метод-инъекцию 😨

Это малоизвестная фича в ASP.NET Core, которая позволяет внедрять зависимости не в конструктор, а напрямую в метод-обработчик.

Для этого используется [FromServices] IYourService

Хотя [FromServices] можно и опустить — оно не обязательно.

Когда стоит использовать метод-инъекцию:

🔸когда сервис используется только в одном экшене
🔸когда конструктор начинает превращаться в кашу из зависимостей
🔸когда сервис тяжёлый, и важно контролировать его создание и утилизацию

Да, внедрение через конструктор — это дефолтный подход.
Но метод-инъекция — это удобный инструмент, если ты:

- хочешь придерживаться Single Responsibility Principle

- не хочешь превращать контроллер в свалку зависимостей

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍107
C# наконец-то получает дискриминируемые объединения

Ну, возможно?

Появилось новое предложение по добавлению объединений типов (Type Unions) в C#. И это действительно важно.

Почему?

Это открывает нативную поддержку таких конструкций, как Result и Option.

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

Я уже много лет выступаю за использование паттерна Result. Но до сих пор отсутствие поддержки на уровне языка делало его применение неуклюжим.


Теперь это может измениться.

В предложении описываются нативные union-типы, включая поддержку pattern matching, проверку исчерпывающего перебора (exhaustiveness checks) и другие фичи.

Не хочешь ждать?

Вот как можно реализовать паттерн Result уже сегодня

Если предпочитаешь бросать исключения — можешь это пропустить. 🤵

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10
Миф о том, что Dapper на 50% быстрее EF Core — это неправда

Ты наверняка слышал, как говорят, что Dapper на 30%, 50% или даже в 2 раза быстрее, чем EF Core?

Это утверждение гуляет повсюду.

Но проведя реальный бенчмарк на .NET 8, с таким запросом:

"Получить топ-5 пользователей, которые оставили больше всего комментариев за последние 7 дней к постам в категории '.NET'"


Результаты удивили:

🔸Dapper: 2.07 мс
🔸EF Core: 2.43 мс
(см. скриншот для деталей)

Разница — всего 0.36 мс, или 14%.

Да, Dapper выделяет меньше памяти, но для большинства приложений эта разница мизерная.

Что это значит?

↳ Для 80% проектов такая разница в производительности вообще не критична.
> Поэтому EF Core — мой выбор по умолчанию.

12 причин выбрать EF Core вместо Dapper в реальной разработке:

1. Автоматическое отслеживание изменений сущностей — меньше ручного кода для insert, update, delete.

2. LINQ-запросы с проверкой на этапе компиляции, которые трансформируются в SQL.

3. Code-First миграции упрощают эволюцию схемы базы данных.

4. Возможность реверс-инжиниринга существующей базы в модели.

5. Навигационные свойства позволяют работать с отношениями без ручных join-ов.

6. Поддержка eager, lazy и explicit загрузки данных.

7. Глобальные фильтры запросов для soft delete и мультиарендности.

8. Value Conversions — удобное отображение кастомных типов на столбцы в БД.

9. Встроенные политики повторных попыток (retry) делают соединения с БД более устойчивыми.

10. Interceptors — можно реализовать аудит, логирование, кастомные поведения.

11. Один и тот же запрос работает с множеством провайдеров: SQL Server, PostgreSQL, MySQL, Oracle, SQLite и др.

12. Поддержка миграций сразу для нескольких БД из одного кода.

Важно:

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

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

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥13👍74🍌1
Как реализовать ограничение частоты запросов для аутентифицированных пользователей?

Можно использовать ID пользователя в качестве ключа разбиения (partition key) для лимитирования.

В .NET есть механизм partitioned rate limiter, который позволяет это настроить.

ID пользователя можно получить из claim'а в JWT или из cookie.

Такую политику лимитирования можно применить:

🔸На уровне API — для простых сценариев
🔸На уровне reverse proxy — при масштабировании

Хочешь узнать о более продвинутых сценариях лимитирования?

Начни отсюда: тык

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍102🍌2
𝟵𝟬% API не являются настоящими RESTful

Веб-API нельзя считать полностью RESTful без "GPS"

Согласно модели зрелости REST по Ричардсону, существует 4 уровня REST-архитектуры:

> Уровень 0 (Swamp of POX): один endpoint, передача XML или JSON без структуры
> Уровень 1 (Resources): выделенные ресурсы с уникальными URI
> Уровень 2 (HTTP-глаголы): корректное использование методов HTTP (GET, POST, PUT, DELETE, PATCH)
> Уровень 3 (HATEOAS): API динамически предоставляет ссылки, направляя клиента по возможным действиям и состояниям

Большинство API застряли на уровне 2, не реализуя HATEOAS.

Что такое HATEOAS?

Hypermedia as the Engine of Application State — "гипермедиа как движок состояния приложения"

Это как GPS для клиента API:

🔸API динамически вшивает ссылки, которые подсказывают клиенту, какие действия доступны
🔸Клиент не хардкодит маршруты, а получает их от сервера
🔸Это делает API гибким и устойчивым к изменениям — даже при эволюции контракта

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

Без HATEOAS:

> Frontend дублирует бизнес-логику с backend'а (например, решает, показывать ли кнопку "Обновить")
> Это приводит к рассинхрону и багам

С HATEOAS:

> Сервер сам отправляет клиенту ссылку на обновление ресурса
> Frontend просто следует ссылке — никакой лишней логики

Такой подход переносит всю сложность туда, где ей место — на backend.

Ты уже используешь HATEOAS в своих API, или твой проект всё ещё застрял на уровне 2?

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍54🥴2🐳2