Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save leojh/6618093 to your computer and use it in GitHub Desktop.
Save leojh/6618093 to your computer and use it in GitHub Desktop.
Code accompanying blog post.
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.ConnectImplementationsToTypesClosing(typeof(AbstractValidator<>));
});
});
public sealed class ValidationActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var actionArgument = GetTheActionArgument(actionContext);
if (actionArgument == null) return;
var validator = GetValidatorForActionArgument(actionArgument);
if (validator == null) return;
var validationResult = validator.Validate(actionArgument);
if (validationResult.IsValid) return;
CreateBadRequestResponse(validationResult);
}
private static IValidator GetValidatorForActionArgument(object actionArgument)
{
var validatorFactory = new StructureMapValidatorFactory();
return validatorFactory.GetValidator(actionArgument.GetType());
}
private static object GetTheActionArgument(HttpActionContext actionContext)
{
return actionContext.ActionArguments.SingleOrDefault().Value;
}
private static void CreateBadRequestResponse(ValidationResult validationResult)
{
var validationErrors =
validationResult.Errors.Select(e => new KeyValuePair<string, string>(e.PropertyName, e.ErrorMessage));
throw new HttpBadRequestResponseException(JsonConvert.SerializeObject(validationErrors));
}
}
public sealed class HttpBadRequestResponseException : HttpResponseException
{
public HttpBadRequestResponseException()
: this(string.Empty)
{
}
public HttpBadRequestResponseException(string message)
: base(new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(message) })
{
}
}
public class StudentInputValidator : AbstractValidator<StudentUpdateModel>
{
public StudentInputValidator()
{
RuleFor(s => s.Id).NotEmpty();
RuleFor(s => s.Balance)
.NotEmpty()
.GreaterThan(0);
}
}
public class StructureMapValidatorFactory : IValidatorFactory
{
private readonly InstanceCache _cache = new InstanceCache();
public IValidator<T> GetValidator<T>()
{
throw new NotSupportedException("Generic implementation is not supported");
}
public IValidator GetValidator(Type type)
{
if (type == null) return null;
var abstractValidatorType = typeof (AbstractValidator<>);
var validatorForType = abstractValidatorType.MakeGenericType(type);
var validator = ObjectFactory.TryGetInstance(validatorForType);
return validator != null ? _cache.GetOrCreateInstance(validator.GetType()) as IValidator : null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment