LSTANCZYK
3/21/2017 - 5:01 PM

AutofacFluentValidationActionFilterAttribute.cs

 [AttributeUsage(AttributeTargets.Method)]
    public class ValidationActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            InnerOnActionExecuting(actionContext);

            var modelState = actionContext.ModelState;

            if (modelState.IsValid)
            {
                return;
            }

            ErrorResource errorResource = BuildErrorResource(modelState);

            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, errorResource);
        }

        private ErrorResource BuildErrorResource(ModelStateDictionary modelState)
        {
            var error = new ErrorResource
                        {
                            Message = "Your request is invalid.",
                            Errors = new Dictionary<string, IEnumerable<string>>()
                        };

            foreach (KeyValuePair<string, ModelState> item in modelState)
            {
                IEnumerable<string> itemErrors = item.Value.Errors.Select(childItem => childItem.ErrorMessage);
                error.Errors.Add(item.Key, itemErrors);
            }

            return error;
        }

        private void InnerOnActionExecuting(HttpActionContext actionContext)
        {
            // Retrieve the dependency scope for the current request 
            // (FluentValidation's FluentValidationModelValidatorProvider and ValidatorFactoryBase does not support this)
            IDependencyScope scope = actionContext.Request.GetDependencyScope();

            foreach (KeyValuePair<string, object> argument in actionContext.ActionArguments)
            {
                IValidator validator = GetScopedValidator(argument.Value.GetType(), scope);

                ValidationResult result = validator.Validate(argument.Value);

                foreach (ValidationFailure error in result.Errors)
                {
                    Trace.WriteLine(error.PropertyName);
                    actionContext.ModelState.Add(error.PropertyName,
                                                 new ModelState
                                                 {
                                                     Value = new ValueProviderResult(error.AttemptedValue, error.AttemptedValue?.ToString() ?? string.Empty, CultureInfo.CurrentCulture)
                                                 });
                    actionContext.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
                }
            }
        }

        private IValidator GetScopedValidator(Type type, IDependencyScope scope)
        {
            Type validatorType = typeof (IValidator<>).MakeGenericType(type);
            IValidator validator = scope.GetService(validatorType) as IValidator;
            return validator;
        }
    }