ASP.NET Проверка ядра: отключите проверку сервера для некоторых свойств динамически

#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 в любом случае.