Last active
January 26, 2017 12:22
-
-
Save asbjornu/d759c98408285dcab421e7494046615e to your computer and use it in GitHub Desktop.
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 class RecursiveDataAnnotationsValidator : IModelValidator | |
{ | |
private readonly IModelValidator validator; | |
public RecursiveDataAnnotationsValidator(IModelValidator innerValidator, Type type) | |
{ | |
if (innerValidator == null) | |
throw new ArgumentNullException(nameof(innerValidator)); | |
if (type == null) | |
throw new ArgumentNullException(nameof(type)); | |
this.validator = innerValidator; | |
Description = CreateDescription(innerValidator, type); | |
} | |
public ModelValidationResult Validate(object instance, NancyContext context) | |
{ | |
// Rewritten to fit into Nancy from: https://github.com/reustmd/DataAnnotationsValidatorRecursive/blob/master/DataAnnotationsValidator/DataAnnotationsValidator/DataAnnotationsValidator.cs | |
var result = this.validator.Validate(instance, context); | |
var properties = instance | |
.GetType() | |
.GetProperties() | |
.Where(prop => prop.CanRead && prop.GetIndexParameters().Length == 0) | |
.ToList(); | |
var errors = result.Errors; | |
foreach (var property in properties) | |
{ | |
if (property.PropertyType == typeof(string) || property.PropertyType.IsValueType) | |
continue; | |
var value = instance.GetPropertyValue(property.Name); | |
if (value == null) | |
continue; | |
var enumerable = value as IEnumerable; | |
if (enumerable != null) | |
{ | |
foreach (var e in enumerable) | |
{ | |
var nestedResult = this.validator.Validate(e, context); | |
Add(nestedResult, property, errors); | |
} | |
} | |
else | |
{ | |
var nestedResult = this.validator.Validate(value, context); | |
Add(nestedResult, property, errors); | |
} | |
} | |
return new ModelValidationResult(errors); | |
} | |
public ModelValidationDescriptor Description { get; } | |
public Type ModelType => this.validator.ModelType; | |
private static void Add(ModelValidationResult nestedResult, | |
PropertyInfo property, | |
IDictionary<string, IList<ModelValidationError>> errors) | |
{ | |
foreach (var kvp in nestedResult.Errors) | |
{ | |
var key = string.Format("{0}.{1}", property.Name, kvp.Key); | |
var modelValidationErrors = kvp.Value.Select(error => Transform(error, property)).ToList(); | |
errors.Add(key, modelValidationErrors); | |
} | |
} | |
private static ModelValidationDescriptor CreateDescription(IModelValidator validator, Type modelType) | |
{ | |
var rules = validator.Description.Rules.ToDictionary(x => string.Format("{0}.{1}", validator.ModelType, x.Key), | |
x => x.Value); | |
return new ModelValidationDescriptor(rules, modelType); | |
} | |
private static ModelValidationError Transform(ModelValidationError error, PropertyInfo property) | |
{ | |
var memberNames = error.MemberNames.Select(n => string.Format("{0}.{1}", property.Name, n)); | |
return new ModelValidationError(memberNames, error.ErrorMessage); | |
} | |
} |
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 class RecursiveDataAnnotationsValidatorFactory : IModelValidatorFactory | |
{ | |
private readonly IModelValidatorFactory modelValidatorFactory; | |
public RecursiveDataAnnotationsValidatorFactory(IPropertyValidatorFactory propertyValidatorFactory, | |
IValidatableObjectAdapter validatableObjectAdapter) | |
{ | |
this.modelValidatorFactory = new DataAnnotationsValidatorFactory(propertyValidatorFactory, validatableObjectAdapter); | |
} | |
public IModelValidator Create(Type type) | |
{ | |
var innerValidator = this.modelValidatorFactory.Create(type); | |
var validator = new RecursiveDataAnnotationsValidator(innerValidator, type); | |
return validator.Description.Rules.Any() | |
? validator | |
: null; | |
} | |
} |
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 class RecursiveDataAnnotationsValidatorLocator : IModelValidatorLocator | |
{ | |
private readonly IModelValidatorFactory modelValidatorFactory; | |
public RecursiveDataAnnotationsValidatorLocator(IPropertyValidatorFactory propertyValidatorFactory, | |
IValidatableObjectAdapter validatableObjectAdapter) | |
{ | |
if (propertyValidatorFactory == null) | |
throw new ArgumentNullException(nameof(propertyValidatorFactory)); | |
if (validatableObjectAdapter == null) | |
throw new ArgumentNullException(nameof(validatableObjectAdapter)); | |
this.modelValidatorFactory = new RecursiveDataAnnotationsValidatorFactory(propertyValidatorFactory, | |
validatableObjectAdapter); | |
} | |
public IModelValidator GetValidatorForType(Type type) | |
{ | |
return this.modelValidatorFactory.Create(type); | |
} | |
} |
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 class RecursiveValidatorBootstrapper : DefaultNancyBootstrapper | |
{ | |
protected override IEnumerable<Type> ModelValidatorFactories => | |
new[] { typeof(RecursiveDataAnnotationsValidatorFactory) }; | |
protected override NancyInternalConfiguration InternalConfiguration => | |
NancyInternalConfiguration.WithOverrides(config => config.ModelValidatorLocator = typeof(RecursiveDataAnnotationsValidatorLocator)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment