Created
November 22, 2019 20:17
-
-
Save fabiomaulo/e3cf9ee41926ba5c43ba98d116142b95 to your computer and use it in GitHub Desktop.
Data Annotations Validator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface IViewModelValidator | |
{ | |
bool IsValid(object model); | |
} | |
public class DataAnnotationsValidator : IViewModelValidator | |
{ | |
private class ReferenceEqualityComparer : IEqualityComparer<object> | |
{ | |
public new bool Equals(object x, object y) | |
{ | |
return ReferenceEquals(x, y); | |
} | |
public int GetHashCode(object obj) | |
{ | |
return RuntimeHelpers.GetHashCode(obj); | |
} | |
} | |
public bool TryValidate(object model, out ICollection<ValidationResult> results) | |
{ | |
var vrs = new List<ValidationResult>(); | |
results = vrs; | |
return TryValidate(model, new HashSet<object>(new ReferenceEqualityComparer()), vrs); | |
} | |
public bool IsValid(object model) | |
{ | |
return TryValidate(model, new HashSet<object>(new ReferenceEqualityComparer()), null); | |
} | |
private bool TryValidate(object model, ISet<object> validatedObjects, List<ValidationResult> results) | |
{ | |
if (validatedObjects.Contains(model)) | |
{ | |
return true; | |
} | |
validatedObjects.Add(model); | |
var shortcircuit = results == null; | |
var context = new ValidationContext(model, serviceProvider: null, items: null); | |
bool result = Validator.TryValidateObject(model, context, results, validateAllProperties: true); | |
var properties = TypeDescriptor.GetProperties(model).Cast<PropertyDescriptor>().ToList(); | |
foreach (var property in properties.Where(p => p.PropertyType != typeof(string) && !p.PropertyType.IsValueType)) | |
{ | |
var value = property.GetValue(model); | |
if (value == null) | |
{ | |
continue; | |
} | |
if (value is IEnumerable asEnumerable) | |
{ | |
foreach (var enumObj in asEnumerable) | |
{ | |
if (enumObj != null) | |
{ | |
var nestedResults = shortcircuit ? null : new List<ValidationResult>(); | |
if (!TryValidate(enumObj, validatedObjects, nestedResults)) | |
{ | |
if (shortcircuit) | |
{ | |
return false; | |
} | |
result = false; | |
results.AddRange(nestedResults.Select(nr => new ValidationResult(nr.ErrorMessage, nr.MemberNames.Select(x => property.Name + '.' + x)))); | |
}; | |
} | |
} | |
} | |
else | |
{ | |
var nestedResults = new List<ValidationResult>(); | |
if (!TryValidate(value, validatedObjects, nestedResults)) | |
{ | |
if (shortcircuit) | |
{ | |
return false; | |
} | |
result = false; | |
results.AddRange(nestedResults.Select(nr => new ValidationResult(nr.ErrorMessage, nr.MemberNames.Select(x => property.Name + '.' + x)))); | |
}; | |
} | |
} | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment