#c# #asp.net-core #model-validation
#c# #asp.net-core #модель-проверка
Вопрос:
Есть ли способ отключить проверку некоторых свойств модели на основе связанного значения модели. Пример:
public class ContactModel
{
public string Name { get; set; }
public string ContactType { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public string Email { get; set; }
}
Это некоторая модель представления, которая должна извлекать имя пользователя, а также его телефон или адрес электронной почты. Если пользователь выбирает одно из них, он должен проверять только выбранное. Но когда телефон выбран и Email
пуст, ModelState.IsValid == false
и наоборот.
Я пытался подключиться к процессу проверки (пользовательскому ValidationAttribute
, IValidatableObject
), но безуспешно, поскольку ValidationContext не предоставляет никакого полезного контекста — мне нужно получить доступ к ContactType
значению при проверке Phone/Email
. Я даже пытался создать пользовательский связующий файл, но подавление проверки на этом этапе не дает ожидаемых результатов, поскольку оно только устанавливает состояние проверки на Непроверенное, которое рассматривается как ModelState.IsValid
.
Единственное решение, которое я нашел до сих пор, — создать ActionFilter/PageFilter
, который обнаружит, существует ли какая-либо модель ContactModel
типа, и удалит ошибки проверки для неиспользуемых полей из ModelState. Но я не чувствую себя комфортно с таким решением (мне это кажется неправильным). Есть какие-нибудь идеи?
Комментарии:
1. Какие-либо обновления? Поможет ли вам мой ответ?
Ответ №1:
Согласно вашему описанию, я предлагаю вам рассмотреть возможность использования пользовательских CustomModelValidator и пользовательских ModelValidator для выполнения ваших требований.
Используя это, мы могли бы получить всю модель, используя ее значение контейнера.
Более подробную информацию вы можете найти в приведенных ниже кодах:
Класс CustomModelValidatorProvider:
public void CreateValidators(ModelValidatorProviderContext context)
{
if (context.ModelMetadata.ContainerType == typeof(ContactModel))
{
context.Results.Add(new ValidatorItem
{
Validator = new ContactModelValidator(),
IsReusable = true
});
}
}
public class ContactModelValidator : IModelValidator
{
private static readonly object _emptyValidationContextInstance = new object();
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext validationContext)
{
var validationResults = new List<ModelValidationResult>();
if (validationContext.ModelMetadata.Name == "Name" amp;amp; validationContext.Model == null)
{
var validationResult = new ModelValidationResult("", "Name is required");
validationResults.Add(validationResult);
}
if (validationContext.ModelMetadata.Name == "ContactType" amp;amp; validationContext.Model == null)
{
var validationResult = new ModelValidationResult("", "ContactType is required");
validationResults.Add(validationResult);
}
if (validationContext.ModelMetadata.Name == "ContactType" amp;amp; validationContext.Model == null)
{
var validationResult = new ModelValidationResult("", "ContactType is required");
validationResults.Add(validationResult);
}
if (validationContext.ModelMetadata.Name == "Phone" || validationContext.ModelMetadata.Name == "Email")
{
if (((ContactModel)validationContext.Container).Phone == null amp;amp; ((ContactModel)validationContext.Container).Email == null)
{
var validationResult = new ModelValidationResult("", "Phone or Email is required");
validationResults.Add(validationResult);
}
}
return validationResults;
}
}
Затем добавьте его в метод startup.cs ConfigureServices:
services.AddControllers(options=> {
options.ModelValidatorProviders.Add(new CustomModelValidatorProvider());
});
Результат:
Комментарии:
1. Хотя это работает, я не могу принять это как ответ. То же, что вы описали, можно сделать намного проще, внедрив
IValidatableObject
ContactModel
и проверив реальные значения модели. Но это моя вина — в стремлении быть как можно более простым я выбрал простой пример. На самом деле в моей модели есть несколько списков и общий аргумент, что делает этот метод бесполезным. Мне пришлось найти другой способ — во время привязки пользовательской модели (что я все равно должен сделать) Я манипулирую темValidationStateEntry
, что отключает проверку для выбранной части подмодели. 1 в любом случае.