Return multiple test exceptions

There was an attempt to include server-side DataAnnotation data validation in my project, and I found that DataAnnotations has its own error type - ValidationException. My problem with this, however, is that it only returns one validation error at a time, so if 3 properties fail the validation, only the first one is selected. I’m looking for a way to throw all errors as an exception, so instead of informing the user / developer that the check did not pass, he will indicate which properties / fields the check failed at one time.

I found the Validator.TryValidateObject (...) method, but it just populates the ValidationResults and leaves the developer with the option to throw and drop or not. What I am currently implementing iterates through ValidationResults to create a list of ValidationExceptions from this, completes the list in an AggregateException, and then throws another ValidationException using the AggregateException in its internal values.

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)); } 

So basically my questions are:

  • Is there a reason why there is no built-in way to throw multiple errors at the same time? That is, is there any good practice missing with DataAnnotation Validations?
  • Is there a better way to achieve what I was trying to implement?
  • Also ... how can I include a member name when moving a ValidationResult to a Validation exception?
+7
c # validation error-handling data-annotations
source share
2 answers

As for your first question, the standard answer to the question “why doesn't the X language support” is just a minus price, and I'm sure that applies here too. This does not often lead to people encountering scenarios that require throwing a few bugs ... Therefore, the people who developed and implemented C # believed that the time it would take for the C # team to develop and implement the "throw some exceptions, "it would be better spent on which provide greater benefits to more people.

And consider the cost to users of the language - wherever you currently have “catch” (Exception e), you will have to do “catch (IEnumerable exceptions)” instead, followed by foreach, in case the API you called with a few exceptions.

As for your second question, I think combining your ValidationExceptions with AggregateException and setting the aggregate as a top-level InnerException ValidationException is a pretty elegant way to approach the problem ... But this is not standard, so hopefully people are “trapped" in this hierarchy exceptions are people you are in close contact with.

You might also consider storing the ValidationResult collection in the Data property of a ValidationException. This is a little easier. The Data property is widely used, but it exists for non-standard scripts like this.

It is difficult to say which of these two approaches is better, but I am inclined to the first. It's trickier, but I think the odds that an arbitrary encoder will detect what you did are a bit higher if you build on InnerException and AggregateException. I mean, when was the last time you dropped the contents of Exception.Data while debugging something? Yes, and I. :-)

Regarding the third question, I think I'm just creating a ValidationException message based on the contents of ValidationResult. Something like "Member {0} is invalid: {1}" for example.

0
source share

Answer your first question: Since each verification attribute has its own IsValid property and returns the result of the verification public ValidationResult(string errorMessage, IEnumerable<string> memberNames); , and you can get the member name from the member name list. Thus, each check did not result in a property return. It is not good that the object has a confirmation that you apply to the property of the object.

Answer the second question: You can create your own ValidationAttribute list for entity verification:

 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); 

Third answer: You can get the member name from ValidationResult :

 public ValidationResult(string errorMessage, IEnumerable<string> memberNames) 
0
source share

All Articles