Manually trigger foolproof validation

3k Views Asked by At

I'm using Foolproof Validation so I can use [RequiredIf] attributes on my view model. The problem is that I'd like to trigger validation within my code using the same logic outside a controller.

I've tried creating my own validation context and using Validatior.TryValidateObject; however, it fails with Foolproof's custom RequiredIf validator. Is there a way to take my model and validate it other than passing it to a controller?

Am I using the wrong approach?

Here is my code:

var draftModel = _draftHelper.LoadDraft(draftId);

var validationResults = new List<ValidationResult>();

var vc = new ValidationContext(draftModel, null, null);

var isValidDraft = Validator.TryValidateObject(draftModel, vc, 
                                               validationResults, true);

And the error I get is on the TryValidateObject line

System.NotImplementedException: The method or operation is not implemented.

2

There are 2 best solutions below

3
On BEST ANSWER

I think a better approach would be to use FluentValidation, not foolproof validation. I personally think Fluent is nicer than attributes too :).

Using FluentValidation, you are also able to validate your model without the use of a Controller.

DraftVM draft = draftRepository.Get(draftId);

var DraftValidator validator = new DraftVMValidator();
ValidationResult results = validator.Validate(draft);

public class DraftVMValidator : AbstractValidator<DraftViewModel>
{
      public DraftVMValidator()
      {

         RuleFor(vm => vm.OptionalField)
            .Must(BeFilledIfNameNotEmpty)
            .WithMessage("Optional Field required because you filled out Name field");
      }


      public bool BeFilledIfNameNotEmpty(DraftVM viewModel)
      {
            return !string.IsNullOrWhiteSpace(viewModel.Name);
      }

} 

This will NOT give you a System.NotImplemented exception.

This validator is DRY because you can also plug it into ASP.NET MVC Validation.
You can simply call the following code in Global.asax or App_Start etc. One validator for all, bind it to MVC Model Validation or use it in any normal application.

FluentValidationModelValidatorProvider.Configure(); // This will bind it for you

If you use Inversion of Control container like Ninject, FluentValidation also has a plugin to work with that. More available on their documentation in link provided above.

I have a pretty big project example in my Github if you want to see more examples of this Validator instead of FoolProof. Example Validators with ASP.NET MVC 4

0
On

You need to let the MVC framework provide your Validator instead of using the Validator.TryValidateObject as below:

var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => viewModelToValidate, viewModelToValidate.GetType());
var compositeValidator = ModelValidator.GetModelValidator(modelMetadata, controller.ControllerContext);
foreach (ModelValidationResult result in compositeValidator.Validate(null))
{
   validationResults.Add(new ValidationResult(result.Message, new List<string> { result.MemberName }));
}