#c# #validation #asp.net-core #asp.net-core-webapi #model-binding
#c# #проверка #asp.net-core #asp.net-core-webapi #привязка к модели
Вопрос:
У меня сложная модель с вложенными объектами. Я хочу , чтобы мои [Required]
атрибуты проверялись только тогда , когда объект , на котором они находятся , таковым не null
является . Так, например, если у меня есть Home
класс со Address
свойством, Home.Address.Street
свойство должно быть только [required]
в том случае, если Address
его нет null
.
Код
В ASP.NET Ядро, у меня есть модель, которая выглядит следующим образом:
public class Home
{
[Required]
public int Number {get;set;}
public Address Address {get;set;} // This is not required
}
public class Address
{
[Required]
public string Street {get;set;}
public IFormFile Picture {get;set;}
}
В контроллере у меня есть метод действия, который выглядит следующим образом:
[HttpPost]
public string AddHomes([FromForm]List<Home> homes)
{
if(!ModelState.IsValid)
{
return BadRequest();
}
// Do some saving
return Ok();
}
И полезная нагрузка формы выглядит следующим образом:
homes.Index: 0
homes[0].number: 1
В ASP.NET Ядро 2.2, первое Home
в homes
списке помечено как недействительное, но оно работало так, как я и ожидал в ASP.NET Ядро 2.1.
Я хочу, чтобы [Required]
атрибут проверялся только в том случае, если Address
это не null
так. Таким образом, a Home
может иметь либо Address
с a, Street
либо Address
вообще не иметь.
Достижимо ли это в .NET Core 2.2?
Примечание: я включил обновленный пример ниже, чтобы воспроизвести ошибку. Похоже, что включение
IFormFile
приводитAddress
к тому, что класс инициализирует сам себя.
{
"errors": {
"homes[0].Address.Street": [
"The Street field is required."
]
},
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "80000009-0003-ff00-b63f-84710c7967bb"
}
Я также открыл проблему на GitHub для этого некоторое время назад, если кто-нибудь захочет продолжить: включение свойства IFormFile заставляет проверять весь объект. ASP.NET Ядро 2.2.
Комментарии:
1. Почему бы вам не удалить [Обязательный] из Street ??
2. Ну, тогда он проанализировал бы объект как not null, и был бы адрес с пустым именем. А также это упрощенный пример. Я хочу знать, как решить проблему, а не изменять предполагаемую функциональность.
3. @Nejdi Я не смог воспроизвести вашу проблему, ASP.NET Ядро 2.2 дало мне
ModelState.IsValid == true
, вы заглянули внутрьModelState.Values
и посмотрели, какое поле было недействительным?4. Привет @Neverever Я обновил пример, чтобы воспроизвести мою ошибку. Похоже, именно включение IFormFile в подмодель привело к его инициализации. Я также включил в обновленный ответ BadRequestError
5. Вы разместили
IFormFile
сообщение в правильной позиции? т. Е.IFormFile
Должны быть размещеныHome[1].Address.Picture
. И, очевидно, публикация вHome[0].Address.Picture
вызовет ошибку проверки.
Ответ №1:
Желаемое поведение — это поведение для свойств нулевой ссылки, и оно не изменилось в ASP.NET Ядро 2.2. Свойства ссылочного класса проверяются только в том случае, если сама ссылка не равна нулю. Если это не работает для вас, то единственный вывод заключается в том, что это ссылочное свойство имеет значение. Это может быть просто создание экземпляра по умолчанию (т.Е. new Foo()
), При этом ни одно из вложенных свойств фактически не определено, но этого достаточно для запуска проверки.
Во-первых, убедитесь, что вы не устанавливаете значение по умолчанию для свойства или иным образом не предоставляете ему значение по умолчанию, например, через конструктор. Другими словами, если у вас есть что-то вроде:
public Bar Bar { get; set; } = new Bar();
Или,
public Foo()
{
Bar = new Bar();
}
Удалите это.
Кроме того, поймите, что если что-либо опубликовано для этого ссылочного свойства, тогда все вступает в игру. Даже если у вас просто есть какое-то скрытое свойство, например:
<input type="hidden" asp-for="Bar.Id" />
Если какое-либо одно свойство в ссылке опубликовано, даже если оно само по себе недопустимо, в игру вступит вся проверка в классе.
Комментарии:
1. Привет @Chris Pratt, я обновил пример, чтобы воспроизвести мою ошибку. Похоже, именно включение IFormFile в подмодель привело к его инициализации. Можете ли вы взглянуть?