尝试将服务器端DataAnnotation验证合并到我的项目中,我发现DataAnnotations有自己的错误类型ValidationException。但是,我的问题在于,它一次只返回一个验证错误,所以如果3个属性验证失败,则只抛出第一个。我正在寻找一种方法将所有错误作为异常抛出,因此它不会通知用户/开发人员验证失败,而是会一次性说明哪些属性/字段验证失败。
我找到了Validator.TryValidateObject(...)方法,但它只是填充ValidationResults并让开发人员选择是否抛出异常。我目前正在实现的是迭代ValidationResults以从中创建ValidationExceptions列表,将列表包装成AggregateException,然后在其InnerExceptions中抛出另一个带有AggregateException的ValidationException。
ValidationContext validationContext = new ValidationContext(entity, null, null);
List<ValidationResult> validationResults = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(entity, validationContext, validationResults, true);
if (!isValid)
{
List<ValidationException> validationErrors = new List<ValidationException>();
foreach (ValidationResult validationResult in validationResults)
{
validationErrors.Add(new ValidationException(validationResult.ErrorMessage);
}
throw new ValidationException("Entity validation failed.", new AggregateException(validationErrors));
}
基本上,我的问题是:
答案 0 :(得分:1)
回答您的第一个问题:
因为每个验证属性都有自己的public ValidationResult(string errorMessage, IEnumerable<string> memberNames);
属性并返回ValidationAttribute
验证结果,您可以从成员名称列表中获取成员名称。因此,每次验证都失败了属性返回isValid。实体对您正在申请实体财产的验证并不是一个好主意。
回答你的第二个问题:
您可以创建自己的var validationResults = new List<ValidationResult>();
var validationAttributes = new List<ValidationAttribute>();
validationAttributes.Add(new CustomValidationAttribute(typeof(ClaimValidator), "ValidateClaim"));
var result = Validator.TryValidateValue(claimObject,
new ValidationContext(claimObject, null, null),
validationResults,
validationAttributes);
列表来验证实体:
ValidationResult
第三回答:
您可以从public ValidationResult(string errorMessage, IEnumerable<string> memberNames)
获取会员名称:
// get navigation bar objc
UINavigationBar *navigationBar= [[self.navigationController.navigationBar subviews]objectAtIndex:0];
//create uiview
UIView* gradientViewnavigationBar = [[UIView alloc] initWithFrame:CGRectMake(0,0,navigationBar.frame.size.width,navigationBar.frame.size.height)];
// create layer of gradient color
CAGradientLayer * gradientLayernavigationBar = [[CAGradientLayer alloc] init];
gradientLayernavigationBar.frame = gradientViewnavigationBar.bounds;
gradientLayernavigationBar.colors = [NSArray arrayWithObjects:(id)[[UIColor redColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
gradientLayernavigationBar.opacity=1.0;
// add layer on view
// then add view on navigation bar
[gradientViewnavigationBar.layer insertSublayer:gradientLayernavigationBar atIndex:0];
[navigationBar insertSubview:gradientViewnavigationBar atIndex:0];
答案 1 :(得分:0)
关于你的第一个问题,“为什么语言不支持X”的标准答案只是成本与效益,我相信这也适用于此。人们常常遇到需要抛出多个错误的场景......所以设计和实现C#的人们认为,C#团队设计和实现“抛出多个异常”功能所需的时间最好花在为更多人提供更多好处的功能。
并考虑语言用户的成本 - 你目前所拥有的“捕获(异常e)”,你必须做的“捕获(IEnumerable例外)”,然后是foreach,in如果您调用的API引发了多个异常。
关于你的第二个问题,我认为将ValidationExceptions与AggregateException相结合并将聚合设置为顶级ValidationException的InnerException是解决问题的一种相当方式......但它不是标准的,所以希望那个异常层次结构的“捕获”方面的人是你与之密切沟通的人。
您也可以考虑将ValidationResult集合存储在ValidationException的Data属性中。这有点简单。 Data属性并未广泛使用,但它存在于非标准方案中,例如此属性。
很难说这两种方法中的哪一种更好,但我倾向于第一种方法。它更复杂,但我认为如果你在InnerException和AggregateException上构建,那么任意编码器发现你所做的事情的可能性要高一些。我的意思是,你在调试时最后一次抛出Exception.Data的内容是什么时候?是的,我也不是。 : - )
关于你的第三个问题,我想我只是根据ValidationResult的内容构建ValidationException的消息。例如“会员{0}无效:{1}”。