Проверка типа данных int на стороне сервера - PullRequest
3 голосов
/ 29 марта 2012

Я сделал пользовательский атрибут Validator

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("");
        }
    }
}

Но когда в моем текстовом поле вместо введенного значения int введена строка, тогда value==null, а после ввода значения int * value==entered value;. Почему?

Есть ли альтернатива, с помощью которой я могу добиться того же (убедитесь только на стороне сервера)

1 Ответ

4 голосов
/ 29 марта 2012

Причина, по которой это происходит, заключается в том, что механизм связывания модели (который запускается до любых валидаторов) не может связать недопустимое значение с целым числом.Вот почему внутри вашего валидатора вы не получите никакой ценности.Если вы хотите проверить это, вы можете написать пользовательское связующее для модели целочисленного типа.

Вот как может выглядеть такое связующее для модели:

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;
    }
}

, и вы зарегистрируете егов Application_Start:

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

Но вы можете спросить: а что если я захочу настроить сообщение об ошибке?В конце концов, это то, чего я пытался достичь в первую очередь.Какой смысл писать эту модель связки, когда стандартная уже делает это для меня, просто я не могу настроить сообщение об ошибке?

Ну, это довольно просто.Вы можете создать пользовательский атрибут, который будет использоваться для украшения вашей модели вида и который будет содержать сообщение об ошибке, а внутри подшивки модели вы сможете получить это сообщение об ошибке и использовать его вместо этого.

Итак,у вас может быть фиктивный атрибут валидатора:

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

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

, который вы можете использовать для украшения вашей модели вида:

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

и адаптировать подшивку модели:

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;
    }
}
...