Since I was trying to solve this problem, I wanted to make sure that the same validator instance could be used for MVC and Web API. I was able to accomplish this by making two factories and using them together.
MVC Factory:
public class MVCValidationFactory : ValidatorFactoryBase { private readonly IKernel _kernel; public MVCValidationFactory(IKernel kernel) { _kernel = kernel; } public override IValidator CreateInstance(Type validatorType) { var returnType = _kernel.TryGet(validatorType); return returnType as IValidator; } }
Factory API:
public class WebAPIValidationFactory : ModelValidatorProvider { private readonly MVCValidationFactory _mvcValidationFactory; private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public WebAPIValidationFactory(MVCValidationFactory mvcValidationFactory) { _mvcValidationFactory = mvcValidationFactory; } public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders) { try { var type = GetType(metadata); if (type != null) { var fluentValidator = _mvcValidationFactory.CreateInstance(typeof(FluentValidation.IValidator<>).MakeGenericType(type)); if (fluentValidator != null) { yield return new FluentValidationModelValidator(validatorProviders, fluentValidator); } } } catch (Exception ex) { Log.Error(ex); } return new List<ModelValidator>(); } private static Type GetType(ModelMetadata metadata) { return metadata.ContainerType != null ? metadata.ContainerType.UnderlyingSystemType : null; }
Then it turned out how to run a test for MVC and Web API. I ended up creating a wrapper for IValidator <>, which worked with the ModelValidator signature.
public class FluentValidationModelValidator : ModelValidator { public IValidator innerValidator { get; private set; } public FluentValidationModelValidator( IEnumerable<ModelValidatorProvider> validatorProviders, IValidator validator) : base(validatorProviders) { innerValidator = validator; } public override IEnumerable<ModelValidationResult> Validate(ModelMetadata metadata, object container) { if (InnerValidator != null && container != null) { var result = innerValidator.Validate(container); return GetResults(result); } return new List<ModelValidationResult>(); } private static IEnumerable<ModelValidationResult> GetResults(FluentValidation.Results.ValidationResult result) { return result.Errors.Select(error => new ModelValidationResult { MemberName = error.PropertyName, Message = error.ErrorMessage })); } }
The last part was connecting validators to Global.asax:
MVCValidationFactory mvcValidationFactory = new MVCValidationFactory(KernelProvider.Instance.GetKernel()); GlobalConfiguration.Configuration.Services.Add( typeof(ModelValidatorProvider), new WebAPIValidationFactory(mvcValidationFactory)); ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(mvcValidationFactory)); DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Sorry, it was a little long, but hopefully this helps someone out.
Joel Feb 22 '13 at 15:02 2013-02-22 15:02
source share