TGStat
TGStat
Type to search
Advanced channel search
  • flag English
    Site language
    flag Russian flag English flag Uzbek
  • Sign In
  • Catalog
    Channels and groups catalog Regional compilations Thematic compilations Платные каналы Search for channels
    Add a channel/group
  • Ratings
    Rating of channels Rating of groups Posts rating
    Ratings of brands and people
  • Analytics
  • Search by posts
  • Telegram monitoring
  • Promotion
    Advertising through Yandex Business Advertising in channels through TGStat Agency Advertising on TGStat.ru website
async / noway — Будни разработчика

28 Apr, 13:21

Open in Telegram Share Report

Давненько ничего не писал про программирование, время исправиться. В нашем любимом .NET очень часто на собесах любят спрашивать про типы данных, про ссылочные и значимые, где большинство отвечает уже на автомате про хранение на стеке / кучи, передача значения или ссылки на значение, боксинг / анбоксинг и аллокации при преобразовании – база, в общем. Недавно столкнулся с одним багом, который прям хорошо так подсвечивает разницу между этими типами, а разбор такого бага на собесе гарантировано покажет интервьюеру, что вы прям хорошо понимаете разницу.

Итак, есть стандартный контроллер с необходимым атрибутом [ApiController], унаследован от базового ControllerBase – все как нужно.
На вход в контроллер придет модель
public class CreateModel
{
[Required]
public string Name { get; set; }
[Required]
public UserStatus Status { get; set; } //enum
[Required]
public bool IsActive { get; set; }
[Required]
public int Percent { get; set; }
}

С первого взгляда все сделано правильно – необходимым поля помечены атрибутом [Required], все поля не могут быть пустыми / nullable, мы теперь ожидаем что эндпоинт будет отклонять запрос, если одно из полей будет пустым. Запускаем приложение, открываем свагер, убираем из модели поле Name, получаем ожидаемый ответ 400 и отправляем МР со спокойной душой.

Но, как вы понимаете, здесь спрятана коварная ошибка, которая в лучшем случае всплывет на тестах. Из-за того что string – ссылочный тип, у него допускается значение null при инициализации. Если ничего не передать с фронта, то при обработке запроса и привязке к моделе, ASP .NET оставит это поле незаполненным, т. е. как есть, а дальше уже вступает в дело атрибут [Required], Name отсутствует и запрос отклоняется. А вот с остальными полями enum UserStatus, bool IsActive и int Percent ситуация интереснее. Они все значимые типы, а у значимых типов не может быть значения null по умолчанию. Поэтому парсер ASP .NET Core читает входящий JSON, видит отсутствие поля UsingService или IsActive и инициализирует эти свойства в вашей модели их значениями по умолчанию. А для int это 0, для bool = false, для Enum – первое значение. И это произойдет автоматически при ModelBinding, а дальше снова вступает в дело атрибут [Required], а все обязательные поля есть и значения имеются. Запрос принимается контроллером, летит куда-то дальше в хэндлер, и, в конечном итоге, некорректное значение падает в базу. И все что нужно, чтобы запрос отклонил эндпоинт, помнить правило: если нам нужно использовать [Required], для значимых типов, всегда делайте их nullable
то есть должно быть
public class CreateModel
{
public UserStatus? Status { get; set; } //enum
public bool? IsActive { get; set; }
public int? Percent { get; set; }
}

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

195 0 2 11
Catalog
Channels and groups catalog Channels compilations Search for channels Add a channel/group
Ratings
Rating of Telegram channels Rating of Telegram groups Posts rating Ratings of brands and people
API
API statistics Search API of posts API Callback
Our channels
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Read
Академия TGStat Telegram Research 2019 Telegram Research 2021 Telegram Research 2023
Contacts
Справочный центр Support Email Jobs
Miscellaneous
Terms and conditions Privacy policy Public offer
Our bots
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot