我有我的视图模型的属性可以接受整型和空的值:
[Display(Name = "Code Postal")]
public int? CodePostal { get; set; }
当我在字符串值输入时,如何可以显示比默认彼此消息:
The field Code Postal must be a number.
谢谢
我有我的视图模型的属性可以接受整型和空的值:
[Display(Name = "Code Postal")]
public int? CodePostal { get; set; }
当我在字符串值输入时,如何可以显示比默认彼此消息:
The field Code Postal must be a number.
谢谢
你可以写一个元数据属性的认识:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class MustBeAValidIntegerAttribute : Attribute, IMetadataAware
{
public MustBeAValidIntegerAttribute(string errorMessage)
{
ErrorMessage = errorMessage;
}
public string ErrorMessage { get; private set; }
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["mustbeavalidinteger"] = ErrorMessage;
}
}
并使用该属性,因为它是增加了,当它结合这些整数类型从请求您看到的硬编码错误消息的默认模型绑定一个自定义的模型绑定:
public class NullableIntegerModelBinder: DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (!bindingContext.ModelMetadata.AdditionalValues.ContainsKey("mustbeavalidinteger"))
{
return base.BindModel(controllerContext, bindingContext);
}
var mustBeAValidIntegerMessage = bindingContext.ModelMetadata.AdditionalValues["mustbeavalidinteger"] as string;
if (string.IsNullOrEmpty(mustBeAValidIntegerMessage))
{
return base.BindModel(controllerContext, bindingContext);
}
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (value == null)
{
return null;
}
try
{
return value.ConvertTo(typeof(int?));
}
catch (Exception)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, mustBeAValidIntegerMessage);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
}
return null;
}
}
这将在注册Application_Start
:
ModelBinders.Binders.Add(typeof(int?), new NullableIntegerModelBinder());
从这一刻开始事情就变得非常标准。
浏览模式:
public class MyViewModel
{
[Display(Name = "Code Postal")]
[MustBeAValidInteger("CodePostal must be a valid integer")]
public int? CodePostal { get; set; }
}
控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
视图:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.CodePostal)
@Html.ValidationMessageFor(x => x.CodePostal)
<button type="submit">OK</button>
}
最简单的方法是,以取代默认的验证资源字符串。 这其他的SO的回答会帮你。
但是,你要记住,这些字符串将他们所有的车型某个类的不只是特定属性的使用。
注 :根据达林(和我没有测试的代码),我击打我的答案的一部分。 通过改变资源字符串的简单方法仍然有效。 我已经做了我自己,我知道它的工作原理。
额外的属性添加到您的属性:
[Display(Name = "Code Postal")]
[RegularExpression("\d+", ErrorMessage = "I'm now all yours...")]
public int? CodePostal { get; set; }
即使你在一个非字符串属性设置正则表达式这应该仍然工作。 如果我们看一下验证代码是这样的:
public override bool IsValid(object value)
{
this.SetupRegex();
string text = Convert.ToString(value, CultureInfo.CurrentCulture);
if (string.IsNullOrEmpty(text))
{
return true;
}
Match match = this.Regex.Match(text);
return match.Success && match.Index == 0 && match.Length == text.Length;
}
我们可以看到,这个验证自动转换值的字符串。 所以,如果你的价值是多少它其实并不重要,因为它会被转换为字符串和正则表达式验证。
这是有点失望看到有关我们所要做的一切时,我们要的是通过默认的模型绑定进行的隐含的验证自定义错误消息的工作量。 原因是DefaultModelBinder
隐藏了一些重要的方法为私有特别是GetValueInvalidResource
和GetValueRequiredResource
。 我希望他们会照顾这个未来。
我想给避免为每个类型创建模型联问题的通用解决方案。
老实说,我还没有在所有的情况下测试了以下实施(例如,结合集合时),但在基本的水平一样 。
因此,这里的做法。
我们有两个自定义属性,有助于通过自定义错误消息为我们的自定义模型粘合剂。 我们可以有一个基类,但是这很好。
public class PropertyValueInvalidAttribute: Attribute
{
public string ErrorMessage { get; set; }
public PropertyValueInvalid(string errorMessage)
{
ErrorMessage = errorMessage;
}
}
public class PropertyValueRequiredAttribute: Attribute
{
public string ErrorMessage { get; set; }
public PropertyValueRequired(string errorMessage)
{
ErrorMessage = errorMessage;
}
}
这里是模型绑定,这是通用的,独立的类型和需要自定义错误消息必需的和无效的验证的照顾。
public class ExtendedModelBinder : DefaultModelBinder
{
protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
{
base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
if (propertyDescriptor.Attributes.OfType<PropertyValueInvalidAttribute>().Any())
{
var attr = propertyDescriptor.Attributes.OfType<PropertyValueInvalidAttribute>().First();
foreach (ModelError error in bindingContext.ModelState[propertyDescriptor.Name]
.Errors.Where(err => String.IsNullOrEmpty(err.ErrorMessage) && err.Exception != null)
.ToList())
{
for (Exception exception = error.Exception; exception != null; exception = exception.InnerException)
{
if (exception is FormatException)
{
bindingContext.ModelState[propertyDescriptor.Name].Errors.Remove(error);
bindingContext.ModelState[propertyDescriptor.Name].Errors.Add(attr.ErrorMessage);
break;
}
}
}
}
}
protected override void OnPropertyValidated(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
{
if (propertyDescriptor.Attributes.OfType<PropertyValueRequiredAttribute>().Any())
{
var attr = propertyDescriptor.Attributes.OfType<PropertyValueRequiredAttribute>().First();
var isTypeAllowsNullValue = (!propertyDescriptor.PropertyType.IsValueType || Nullable.GetUnderlyingType(propertyDescriptor.PropertyType) != null);
if (value == null && !isTypeAllowsNullValue)
{
bindingContext.ModelState[propertyDescriptor.Name].Errors.Clear();
bindingContext.ModelState.AddModelError(propertyDescriptor.Name, attr.ErrorMessage);
}
}
base.OnPropertyValidated(controllerContext, bindingContext, propertyDescriptor, value);
}
}
我们覆盖的OnPropertyValidated
方法只覆盖由默认的模型绑定抛出的隐含所需的错误消息,我们正在重写SetProperty
只是用我们自己的消息时,该类型无效。
我们设置定制绑定在Global.asax.cs中默认
ModelBinders.Binders.DefaultBinder = new ExtendedModelBinder();
你可以装饰你的属性这样的..
[PropertyValueRequired("this field is required")]
[PropertyValueInvalid("type is invalid")]
[Display(Name = "Code Postal")]
public int? CodePostal { get; set; }