Custom Model Binder Not Validating Model

半世苍凉 提交于 2019-12-03 12:01:23

Description

The FromJsonAttribute only binds to the model and does, like you said, no validation.

You can add validation to the FromJsonAttribute in order to validate the model's against his DataAnnotations attributes.

This can be done using the TypeDescriptor class.

TypeDescriptor Provides information about the characteristics for a component, such as its attributes, properties, and events.

Check out my solution. I have tested it.

Solution

private class JsonModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
        if (string.IsNullOrEmpty(stringified))
            return null;
        var model = serializer.Deserialize(stringified, bindingContext.ModelType);

        // DataAnnotation Validation
        var validationResult = from prop in TypeDescriptor.GetProperties(model).Cast<PropertyDescriptor>()
                                from attribute in prop.Attributes.OfType<ValidationAttribute>()
                                where !attribute.IsValid(prop.GetValue(model))
                                select new { Propertie = prop.Name, ErrorMessage = attribute.FormatErrorMessage(string.Empty) };

        // Add the ValidationResult's to the ModelState
        foreach (var validationResultItem in validationResult)
            bindingContext.ModelState.AddModelError(validationResultItem.Propertie, validationResultItem.ErrorMessage);

        return model;
    }
}

More Information

Thank you, thank you, dknaack!! Your answer was exactly what I was looking for, except I want to validate after each property is bound b/c I have properties that are dependent on other properties, and I don't want to continue binding if a dependent property is invalid.

Here's my new BindProperty overload:

protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor){

    // if this is a simple property, bind it and return
    if(_simplePropertyKeys.ContainsKey(propertyDescriptor.Name)){
        this.BindSimpleProperty(bindingContext, propertyDescriptor);

    // if this is complex property, only bind it if we don't have an error already
    } else if (bindingContext.ModelState.IsValid){
        this.BindComplexProperty(bindingContext, propertyDescriptor);
    }

    // add errors from the data annotations
    propertyDescriptor.Attributes.OfType<ValidationAttribute>()
        .Where(a => a.IsValid(propertyDescriptor.GetValue(bindingContext.Model)) == false)
        .ForEach(r => bindingContext.ModelState.AddModelError(propertyDescriptor.Name, r.ErrorMessage));
}

First of all, I'm only starting to learn ASP.NET so don't take my solution seriously. I found this article and as you, tried to do a custom model binder. There was no validation. Then i just replaced IModelBinder interface with DefaultModelBinder and voula, it works. Hope I could help someone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!