Как я могу использовать атрибуты проверки данных в C # в не-ASPP.net контексте? - PullRequest
30 голосов
/ 24 сентября 2010

Я хотел бы использовать атрибуты проверки данных в сборке библиотеки, чтобы любой пользователь данных мог проверить их без использования ModelBinder (например, в консольном приложении). Как я могу это сделать?

Ответы [ 3 ]

50 голосов
/ 24 сентября 2010

На самом деле это довольно круто. Я недавно использовал его в реализации проверки ВПП. Большинство людей заканчивают тем, что пишут много кода, используя отражение для итерации атрибутов, но для этого есть встроенная функция.

var vc = new ValidationContext(myObject, null, null);
return Validator.TryValidateObject(myObject, vc, null, true);

Вы также можете проверять атрибуты для одного именованного свойства. Вы также можете при желании передать список для доступа к сообщениям об ошибках:

var results = new List<ValidationResult>();
var vc = new ValidationContext(myObject, null, null) { MemberName = "UserName"};
var isValid = Validator.TryValidateProperty(value, vc, results);

// get all the errors
var errors = Array.ConvertAll(results.ToArray(), o => o.ErrorMessage);
2 голосов
/ 24 сентября 2010

Классы System.ComponentModel.DataAnnotations.ValidationAttribute имеют IsValid методы, которые выполняют логику проверки.Они берут Object (значение поля, которое они украшают) и возвращают true или false.

Вы можете использовать эти атрибуты и немного размышлений, чтобы создать свой собственный аспектно-ориентированный валидатор.Передайте вашему валидатору объект, и валидатор получит список PropertyInfo s и FieldInfo s.Для каждого из них он может вызвать GetCustomAttributes для поиска тех, которые наследуются от ValidationAttribute, а для каждого из них вызвать IsValid, передав значение свойства или поля.Это можно сделать полностью динамически, не зная структуры класса, который будет проверяться во время разработки.

0 голосов
/ 28 июня 2018

TryValidateProperty просто плохо написано - вы должны перепрыгнуть через обручи, чтобы заставить его работать вне контроллера, и даже тогда, если вы используете его дважды, он в конечном итоге тихо установит ModelState в значение valid / invalid и прекратит alterring это состояние, и прекратить возвращать точные результаты с тех пор.

Я отказался от этого и просто написал свой собственный валидатор. Это зациклит любой набор объектов в любом контексте и скажет вам, если они действительны:

bool isValid = true;
var invalidFields = new List<string>();

foreach (var o in viewModels)
{
    var properties = o.GetType()
        .GetProperties(BindingFlags.Public | BindingFlags.Instance);
    foreach(var prop in properties)
    {
        var attrs = prop.GetCustomAttributes(true);
        if (attrs != null)
        {
            var val = prop.GetValue(o);
            ValidationAttribute[] validatorAttrs = attrs
                .Where(a => a is ValidationAttribute)
                .Select(a => (ValidationAttribute)a).ToArray();

            foreach(var attr in validatorAttrs)
            {                       
                bool thisFieldIsValid = attr.IsValid(val);
                if (!thisFieldIsValid)
                    invalidFields.Add(prop.Name);

                isValid = isValid && thisFieldIsValid;
            }
        }
    }
}
...