发生这种情况的原因是模型绑定器(运行before任何验证器)无法将无效值绑定到整数。这就是为什么在你的验证器中你没有获得任何价值。如果您希望能够验证这一点,您可以为整数类型编写一个自定义模型绑定程序。
此类模型绑定器如下所示:
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;
}
}