C#/.NET-разработчик
80 задач. Условие и варианты ответа открыты всем; проверка, подсказка и разбор — в клубе.
C# и ASP.NET Core
- Передача struct и class в метод: что напечатает код
- Что означает AddScoped в ASP.NET Core Web API
- Какой ответ вернуть на успешный POST, создавший заказ
- Вызов .Result внутри контроллера под нагрузкой
- Middleware без вызова next: что получит клиент
- throw ex в блоке catch: что теряется при таком перевыбросе
- Singleton зависит от DbContext: захваченная зависимость
- ConcurrentDictionary.GetOrAdd под параллельной нагрузкой
Entity Framework Core и LINQ
- Когда LINQ-запрос EF Core реально уходит в базу
- Что даёт AsNoTracking в запросе только на чтение
- Обращение к навигационному свойству без Include
- Метод C# внутри Where: почему запрос не переводится в SQL
- Фильтрация после ToListAsync: почему такой метод опасен
- Два Include коллекций: декартов взрыв в одном запросе
- SaveChanges вернул 0 после правки сущности из AsNoTracking-запроса
- Include перед Select: почему ревьюер просит его убрать
SQL и оптимизация запросов
- Цена индекса: что ускорится, а что подорожает
- Сколько строк вернёт LEFT JOIN клиентов и заказов
- COUNT(*) и COUNT(колонка) на данных с NULL
- Составной индекс (customer_id, created_at): какие запросы им воспользуются
- Функция над колонкой в WHERE и неработающий индекс
- NOT IN с подзапросом, где встречается NULL
- Индекс добавили, а план по-прежнему показывает полное сканирование
- Два одновременных списания: потерянное обновление баланса
Кэш, очереди и микросервисы
- IMemoryCache в сервисе, развёрнутом в нескольких репликах
- Потребитель RabbitMQ лежал 20 минут: что стало с сообщениями
- После обновления контейнера пропали загруженные файлы
- Обновили тариф в базе, а API шесть часов отдаёт старую цену
- Повторная доставка сообщения привела к двойному списанию
- Заказ сохранён, событие не отправлено: разъехавшиеся состояния
- События одного заказа приходят не в том порядке
- Одновременное истечение ключей кэша кладёт базу
async/await, многопоточность и фоновые задачи
- Под нагрузкой сервис не может открыть соединение к API курсов валют
- Исключение в методе отправки письма роняет весь процесс сервиса
- Пользователь закрыл вкладку, а тяжёлый отчёт продолжает выполняться в базе минуту
- Карточка товара собирается из трёх сервисов и отвечает за полторы секунды
- Код обновления токена с await внутри lock не компилируется
- Фоновое обновление статистики падает с ObjectDisposedException
- Parallel.ForEach с async-лямбдой завершается раньше, чем отправлены уведомления
- Из трёх упавших вызовов в логе видна только одна ошибка
- Запросы к зависшему сервису доставки держат потоки по 100 секунд
- Ревьюер требует ставить ConfigureAwait(false) на каждый await в Web API
- Исключение в фоновом обработчике очереди останавливает весь веб-сервис
- Очередь задач в памяти на ConcurrentQueue раздулась до нескольких гигабайт
Архитектура приложения: DI, Clean Architecture, CQRS
- Контроллер заказов разросся до 1 500 строк с запросами к базе и расчётом скидок
- Опечатка в ключе конфигурации обнаружилась только при первом платеже в проде
- Сервис уведомлений невозможно протестировать без реального SMTP-сервера
- В каждый сервис внедрён IServiceProvider, а зависимости достаются через GetService
- У каждого из 180 классов проекта есть интерфейс с единственной реализацией
- Доменная модель заказа ссылается на DbContext и HttpClient
- Список заказов в админке грузит агрегаты с шестью Include ради пяти колонок
- Отменённый заказ смогли оплатить, потому что проверку статуса забыли в одном сервисе
- Добавление способа доставки требует правок switch в пяти местах
- В 60 обработчиках команд копируется одинаковый код валидации, логирования и транзакции
- Клиент получил письмо об оформлении заказа, которого нет в базе
- Команда из шести разработчиков хочет разбить монолит на двенадцать микросервисов
Тестирование: xUnit, Moq, WebApplicationFactory
- Счётчик в поле тестового класса xUnit всегда равен единице
- Пять одинаковых тестов расчёта доставки отличаются только весом посылки
- Тест сервиса скидок падает с NullReferenceException внутри кода, а не в проверке
- Один тест проверяет создание заказа, скидку, письмо, остатки и логирование
- Тест истечения промокода падает в последний день месяца
- Тесты на EF Core InMemory зелёные, а в проде падает уникальный индекс по email
- Как протестировать весь конвейер API, подменив только платёжный шлюз
- Безобидный рефакторинг сервиса сломал 40 тестов с Verify
- Интеграционные тесты клиента CRM зависят от песочницы партнёра
- Интеграционные тесты падают случайно, когда классов с базой стало больше двух
- Покрытие 92%, но мутационное тестирование показало, что тесты почти ничего не проверяют
- Тесты проходят по отдельности, а в полном прогоне один из них падает
Конфигурация, контейнеры и эксплуатация .NET-сервиса
- Пароль от продовой базы лежит в appsettings.Production.json в репозитории
- Переменная окружения Payment:ApiKey не подхватывается в контейнере на Linux
- Образ API на .NET весит 900 МБ и содержит SDK и исходники
- При ошибке API в проде отдаёт страницу со стектрейсом и строками кода
- При недоступной базе все поды API перезапускаются по кругу
- После перехода на .NET 8 сервис в Kubernetes перестал отвечать на проверки
- В Seq и Kibana нельзя отфильтровать логи по номеру заказа, хотя он есть в сообщении
- Четыре реплики при старте одновременно применяют миграции EF Core
- Объём логов вырос в двадцать раз после включения уровня Information в проде
- При деплое обработчик сообщений RabbitMQ обрывается посреди длинной операции
- Трасса запроса обрывается на публикации сообщения в RabbitMQ
- Один партнёр шлёт 5 000 запросов в секунду и замедляет API для всех остальных
