ASP.NET MVC: как выполнить валидацию аннотаций данных на уровне сервиса? - PullRequest
4 голосов
/ 14 октября 2009

В недавнем вопросе, заданном здесь: ASP.NET MVC: достаточно ли проверки аннотаций данных?

... был сделан вывод о том, что полагаться на проверку аннотации данных (вызванную механизмом связывания модели) было недостаточно, чтобы гарантировать, что проверка всегда выполнялась. Нам все еще нужно добавить ту же логику проверки на уровне сервисов (или где-то еще после того, как произойдет ModelBinding). К сожалению, в этом заключается то, что мы будем дублировать наш проверочный код (один раз с аннотациями данных и снова на уровне сервисов). Есть ли простой способ для сервисного уровня инициировать проверку на основе того, что было определено в аннотациях данных? Если это возможно, то мы получим лучшее из обоих миров ... нам не нужно будет повторять код проверки, но мы все равно будем следить за тем, чтобы проверка всегда выполнялась.

Ответы [ 3 ]

4 голосов
/ 15 октября 2009

С помощью этого блога: http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/ Мне удалось создать метод, который будет проверять мой объект на основе проверок, определенных аннотациями данных. Он выполнит любой атрибут проверки, полученный из ValidateAttribute. Теперь я могу передать свой объект этому методу из моего сервисного уровня (или DomainModel), и мой сервисный уровень больше не зависит от контроллера. Это гарантирует, что проверка всегда будет выполняться до сохранения данных в базе данных. Я не мог использовать код в блоге как есть, так как у меня, похоже, нет доступа к некоторым методам расширения, которые использовал Грэм, поэтому вот моя версия:

    public static IList<KeyValuePair<string, string>> GetErrors(object obj)
    {
        // get the name of the buddy class for obj
        MetadataTypeAttribute metadataAttrib = obj.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault() as MetadataTypeAttribute;

        // if metadataAttrib is null, then obj doesn't have a buddy class, and in such a case, we'll work with the model class
        Type buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : obj.GetType();

        var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
        var modelClassProperties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();

        var errors = from buddyProp in buddyClassProperties
                           join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name // as this is an inner join, it will return only the properties that are in both the buddy and model classes
                           from attribute in buddyProp.Attributes.OfType<ValidationAttribute>() // get only the attributes of type ValidationAttribute
                           where !attribute.IsValid(modelProp.GetValue(obj))
                           select new KeyValuePair<string, string>(buddyProp.Name, attribute.FormatErrorMessage(string.Empty));

        return errors.ToList();
    }

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

0 голосов
/ 18 декабря 2016

Я хотел добиться того же и попробовал ответ Джонни. Он работает нормально, пока у вас нет проверок, относящихся к другим свойствам, например, с использованием атрибута RequiredIf.

В итоге я использовал класс Validator в System.ComponentModel.DataAnnotations, который фактически предназначен для этого и должен применять ту же самую полную логику, которая обычно применяется.

Это пример метода, который показывает, как это сделать с помощью класса Validator.

    public static bool TryValidate(object obj, List<ValidationResult> results = null)
    {
        var context = new ValidationContext(obj, serviceProvider: null, items: null);
        return Validator.TryValidateObject(obj, context, results, true);
    }
0 голосов
/ 14 октября 2009

Разве вы не проверили мой ответ в вашем предыдущем вопросе?
Я представил некоторый код, который выполняет автоматическую проверку на основе атрибутов DataAnnotation DTO. Пока ваши DTO используются в параметрах вашего действия контроллера, они будут извлечены этим атрибутом и проверены независимо от того, что.

Единственный вопрос: как вы генерируете свои DTO?

  1. Ты сам пишешь их?
  2. Вы используете EF или что-то подобное?
  3. Вы автоматически генерируете их, используя какую-то другую технику (например, T4)?

Если вы можете контролировать генерацию своего класса DTO, то вы также можете добавить к ним дополнительный интерфейс. Код, который я разместил, использует T4 поверх EF, xVal и DataAnnotation и пользовательский интерфейс, который объявляет метод Validate(), который реализован в каждом классе сущности.

...