Server side validation of int type

I made a custom Validator attribute

partial class DataTypeInt : ValidationAttribute
{
    public DataTypeInt(string resourceName)
    {
        base.ErrorMessageResourceType = typeof(blueddPES.Resources.PES.Resource);
        base.ErrorMessageResourceName = resourceName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string number = value.ToString().Trim();
        int val;
        bool result = int.TryParse(number,out val );
        if (result)
        {
            return ValidationResult.Success;
        }
        else 
        {
            return new ValidationResult("");
        }
    }
}

      

But when entered string instead of int value in my textbox then value==null

and when I entered int value then value==entered value;

. Why?

Is there any alternative where I can achieve the same (make sure server side only)

+3


source to share


1 answer


The reason this happens is because model binding (which runs before any validators) is unable to bind an invalid value to an integer. This is why, inside your validator, you are not getting any value. If you want to test this, you can write your own model binder for the integer type.

This is what such a linking device looks like:

public class IntegerBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        int temp;
        if (value == null || 
            string.IsNullOrEmpty(value.AttemptedValue) || 
            !int.TryParse(value.AttemptedValue, out temp)
        )
        {
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, "invalid integer");
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
            return null;
        }

        return temp;
    }
}

      

and you will register it in Application_Start

:

ModelBinders.Binders.Add(typeof(int), new IntegerBinder());

      

But you might ask: what if I want to customize the error message? After all, this is what I was trying to achieve in the first place. What's the point of writing this model binding when by default it already does it for me, it's just that I can't customize the error message?

Ok, that's pretty easy. You can create a custom attribute that will be used to decorate your view model and that will contain the error message, and inside the model binder you can get that error message and use it instead.



So, you might have a dummy validation attribute:

public class MustBeAValidInteger : ValidationAttribute, IMetadataAware
{
    public override bool IsValid(object value)
    {
        return true;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["errorMessage"] = ErrorMessage;
    }
}

      

which you can use to decorate your view model:

[MustBeAValidInteger(ErrorMessage = "The value {0} is not a valid quantity")]
public int Quantity { get; set; }

      

and adapt the model binder:

public class IntegerBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        int temp;
        var attemptedValue = value != null ? value.AttemptedValue : string.Empty;

        if (!int.TryParse(attemptedValue, out temp)
        )
        {
            var errorMessage = "{0} is an invalid integer";
            if (bindingContext.ModelMetadata.AdditionalValues.ContainsKey("errorMessage"))
            {
                errorMessage = bindingContext.ModelMetadata.AdditionalValues["errorMessage"] as string;
            }
            errorMessage = string.Format(errorMessage, attemptedValue);
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, errorMessage);
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
            return null;
        }

        return temp;
    }
}

      

+4


source







All Articles