如何确定不可预测的 LINQ 查询结果的来源?
我一直在开发一个使用 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);
}
I've been working on an application that uses xVal's server side validation with data annotations. We recently ran into errors where the validation messages have been unpredictable for fields that have multiple validations that could fail if the field is empty (e.g., an email address is required, but also fails a validity check).
Assuming that I needed to just return the first validation error, I added a method to our validation runner to achieve that goal (UPDATE: see edit at the bottom for the exact method):
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);
}
I also set up a simple test method to verify in 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"));
}
The problem is that this test's output is highly unpredictable. Sometimes it passes, sometimes it returns just one or two of the errors, and sometimes none at all. Is the issue here with my LINQ query, my test, or both?
EDIT: Great point on pasting in a slightly different method; here's the one actually being hit:
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
摆脱
Take(1)
。我怀疑空字符串正在通过Required
测试。如果您碰巧得到它而不是长度验证器,则测试通过。Get rid of the
Take(1)
. I suspect the empty string is passing theRequired
test. If you happen to get that instead of the length validator, the test passes.尝试使用
Try to use