Search code examples
asp.net-mvcvalidationfluentvalidationcustom-model-binder

How do I re-validate my model in a custom model binder inheriting from DefaultModelBinder after modifying it?


I have a custom model binder inheriting from DefaultModelBinder. What I want it to do is to set a property on the model, that can't be resolved by the DefaultModelBinder. It looks like this:

public class FooModelBinder : DefaultModelBinder  {
  public override void BindModel(ControllerContext controllerContext, ModelBindingContext modelBindingContext) 
  {
    var model = base.BindModel(controllerContext, bindingContext);
    ((IFooModel)model).Bar = GetBarFromSomewhere();

    return model;
  }
}

However, since the Bar property in IFooModel cannot be null and I'm using FluentValidation with a rule saying that, the ModelState will be invalid after I've called base.BindModel.

So I would like to either avoid validating the model when calling base.BindModel, or at least clear the errors and re-validate the model after I've set the Bar property.

I've tried resolving the validators and validating the model, but I can't seem to get it to actually run the validation, and it doesn't result in any errors (even when it should):

var validators = bindingContext.ModelMetadata.GetValidators(controllerContext);
foreach(var validator in validators) {
    foreach (var result in validator.Validate(model)) {
        bindingContext.ModelState.AddModelError(result.MemberName, result.Message);
    }
}

After running this before I return model, validators contains a FluentValidationModelValidator, but when I call validator.Validate I don't get any errors. I have another property on my model which did cause an error when I ran base.BindModel earlier, so I would expect the same error to occur here.


Solution

  • Instead of overriding the BindModel method you could try overriding the BindProperty method:

    public class FooModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
        {
            if (propertyDescriptor.Name == "Bar")
            {
                var model = bindingContext.Model as IFooModel;
                if (model != null)
                {
                    model.Bar = GetBarFromSomewhere();
                }
            }
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }