Question

I use Ninject, MVC4, AutoMapper and FluentValidation glued together.

I have written a validator for my view model and I have written a reusable validator that must be invoked within the view model validator.

The issue is that when I post the form, the Validate override is not called on the view model validator, so the reusable validator is also not called, so in the end the ModelResult is valid... (causing an exception when writing the entity to the DB)...

The strange thing is, that when I added a RuleFor for one of the properties, the form is nicely being validated.

public class RequiredSourceViewModelValidator : AbstractValidator<RequiredSourceViewModel>
    {
        public RequiredSourceViewModelValidator()
        {
            Mapper.CreateMap<RequiredSourceViewModel, Source>();
        }

        public override FluentValidation.Results.ValidationResult Validate(RequiredSourceViewModel requiredSourceViewModel)
        {
            var validator = new SourceValidator();

            var source = Mapper.Map<RequiredSourceViewModel, Source>(requiredSourceViewModel);

            return validator.Validate(source);
        }
    }


public class SourceValidator : AbstractValidator<Source>
    {
        public SourceValidator()
        {
            RuleFor(s => s.Name)
                .NotEmpty()
                    .WithMessage("Naam mag niet leeg zijn.")
                .Length(1, 100)
                    .WithMessage("Naam mag niet langer zijn dan 100 karakters.");

            RuleFor(s => s.Url)
                .NotEmpty()
                    .WithMessage("Url mag niet leeg zijn.")
                 .Must(BeAValidUrl)
                    .WithMessage("Url is niet geldig.")
                .Length(1, 100)
                    .WithMessage("Url mag niet langer zijn dan 100 karakters.");
        }

        private bool BeAValidUrl(string url)
        {
            if (url == null)
            {
                return true;
            }

            var regex = new Regex(@"^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$");
            return regex.IsMatch(url);
        }
    }

public class Source : IEntity
    {
        /// <summary>
        /// Gets or sets the primary key of the source.
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// Gets or sets the name of the source.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the url of the source.
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// Gets or sets the ordinal of the source.
        /// </summary>
        /// <value>
        /// The ordinal of the source.
        /// </value>
        public int Ordinal { get; set; }

        public int? GameId { get; set; }
    }

What could be wrong here ?

Was it helpful?

Solution

You are overriding the wrong overload. You need override the Validate method with the signature: public virtual ValidationResult Validate(ValidationContext<T> context) becuase this method will be called during the MVC validation:

public override ValidationResult Validate(
      ValidationContext<RequiredSourceViewModel> context)
{
     var validator = new SourceValidator();

     var source = 
         Mapper.Map<RequiredSourceViewModel, Source>(context.InstanceToValidate);

     return validator.Validate(source);
 }

The other overload is only used if you manually call validate like validator.Validate(object).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top