Reputation: 16012
Summary of question: is it possible to clear the list of errors from the model state when a fluent validator is resolved for a particular model? That way fluent validation overrides the default behaviour in the data annotation model provider, rather than compliments it?
I am using fluent validation like this:
FluentValidationModelValidatorProvider.Configure(
_ =>
{
// This does not seem to work, or i am misunderstanding it?
_.AddImplicitRequiredValidator = false;
});
I use autofac for a container, but fluent validation is not actually using the container yet. I have it configured as above.
I have a model like this:
[Validator(typeof(PartyModelValidator))]
public class PartyModel
{
The validator validates like this...
public class PartyModelValidator : AbstractValidator<PartyModel>
{
/// <summary>
/// Initialises a new instance of the <see cref="PartyModelValidator"/> class.
/// </summary>
public PartyModelValidator()
{
this.RuleFor(_ => _.Client)
.SetValidator(new ClientValidator())
.When(_ => _.SelectedPartyTab == PartyType.Person);
this.RuleFor(_ => _.Organisation)
.SetValidator(new OrganisationValidator())
.When(_ => _.SelectedPartyTab == PartyType.Organisation);
The validation is working as it should, except that there are [Required]
attributes on some of the person and organisation objects.
These [Required]
attributes are appearing as validation errors. I get these errors even when the entire object is actually null.
How do I get fluent validation to ignore data annotation properties when a specific fluent validator is configured as above? I would prefer to leave the annotations on the objects, as they serve other purposes besides just view validation?
Upvotes: 2
Views: 2693
Reputation: 16012
This does the trick, in case anyone else needs the code, here it is.
/// <summary>
/// The fluent validation model validator provider ex.
/// </summary>
internal class FluentValidationModelValidatorProviderEx : FluentValidationModelValidatorProvider
{
/// <summary>
/// Initialises a new instance of the <see cref="FluentValidationModelValidatorProviderEx"/> class.
/// </summary>
/// <param name="validatorFactory">
/// The validator factory.
/// </param>
public FluentValidationModelValidatorProviderEx(IValidatorFactory validatorFactory) : base(validatorFactory)
{
}
/// <summary>
/// get the fluent validators.
/// </summary>
/// <param name="metadata">The metadata.</param>
/// <param name="context">The context.</param>
/// <returns>the set of validators, if any validators are resolved.</returns>
/// <remarks>If the fluent validator(s) are supplied, then clear the current set of model errors.</remarks>
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
var validators = base.GetValidators(metadata, context);
var modelValidators = validators as ModelValidator[] ?? validators.ToArray();
if (modelValidators.Any())
context.Controller.ViewData.ModelState.Clear();
return modelValidators;
}
/// <summary>
/// configure fluent validation.
/// </summary>
/// <param name="configurationExpression">The configuration expression.</param>
internal static void ConfigureFluentValidation(Action<FluentValidationModelValidatorProvider> configurationExpression = null)
{
configurationExpression = configurationExpression ?? (Action<FluentValidationModelValidatorProvider>)(param0 => { });
FluentValidationModelValidatorProvider validatorProvider = new FluentValidationModelValidatorProviderEx((IValidatorFactory)null);
configurationExpression(validatorProvider);
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
ModelValidatorProviders.Providers.Add((ModelValidatorProvider)validatorProvider);
}
}
Upvotes: 1