Как определить источник непредсказуемых результатов запроса LINQ? - PullRequest
2 голосов
/ 15 февраля 2010

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

Предполагая, что мне нужно было просто вернуть первую ошибку проверки, я добавил метод к нашему исполнителю проверки для достижения этой цели ( ОБНОВЛЕНИЕ : точный метод см. В правке внизу):

public static IEnumerable<ErrorInfo> GetFirstErrors<T>(object instance) where T : ValidationAttribute
    {
        return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
               from attribute in prop.Attributes.OfType<T>().Take(1)
               where !attribute.IsValid(prop.GetValue(instance))
               select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
    }

Я также настроил простой метод тестирования для проверки в NUnit:

private class FirstErrorValidationTest
    {
        [RequiredValueValidator(ErrorMessage = "This field is required"), StringLength(50)]
        public string FirstName { get; set; }

        [RequiredValueValidator(ErrorMessage = "This field is required"), StringLength(50)]
        public string LastName { get; set; }

        [RequiredValueValidator(ErrorMessage = "This field is required"), EmailAddressValidator, StringLength(50)]
        public string EmailAddress { get; set; }
    }

    [Test]
    public void Assert_GetFirstErrors_Gets_First_Listed_Validation_Attribute_Error_Messages()
    {
        FirstErrorValidationTest test = new FirstErrorValidationTest()
        {
            FirstName = "",
            LastName = "",
            EmailAddress = ""
        };

        var errors = DataAnnotationsValidationRunner.GetFirstErrors(test);

        Assert.AreEqual(3, errors.Count());

        foreach (var error in errors)
            Assert.IsTrue(error.ErrorMessage.Contains("required"));
    }

Проблема в том, что результаты этого теста крайне непредсказуемы. Иногда это проходит, иногда возвращает только одну или две ошибки, а иногда и вовсе нет. Проблема здесь с моим запросом LINQ, моим тестом или обоими?

РЕДАКТИРОВАТЬ: Отличный момент при вставке немного другим способом; вот тот, кого действительно ударили:

    public static IEnumerable<ErrorInfo> GetFirstErrors(object instance)
    {
        return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
               from attribute in prop.Attributes.OfType<ValidationAttribute>().Take(1)
               where !attribute.IsValid(prop.GetValue(instance))
               select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
    }

Ответы [ 2 ]

2 голосов
/ 15 февраля 2010

Избавьтесь от Take(1). Я подозреваю, что пустая строка проходит тест Required. Если у вас случится , чтобы получить его вместо валидатора длины, тест пройден.

0 голосов
/ 15 февраля 2010

Попробуйте использовать

var errors = DataAnnotationsValidationRunner.GetFirstErrors(test).ToArray();
...