如何在由@Html助手生成的MVC中更改“data-val-number”消息validation

假设这个模型:

Public Class Detail ... <DisplayName("Custom DisplayName")> <Required(ErrorMessage:="Custom ErrorMessage")> Public Property PercentChange As Integer ... end class 

和观点:

 @Html.TextBoxFor(Function(m) m.PercentChange) 

将继续这个HTML:

  <input data-val="true" data-val-number="The field 'Custom DisplayName' must be a number." data-val-required="Custom ErrorMessage" id="PercentChange" name="PercentChange" type="text" value="0" /> 

我想自定义data-val-number错误消息,我猜是因为PercentChange是一个Integer 。 我正在寻找这样一个属性来改变它, range或任何相关的不工作。
我知道有机会编辑不引人注目的js文件本身或在客户端覆盖它。 我想改变data-val-number的错误信息就像服务器端的其他人一样。

这不是一件容易的事情。 默认消息作为embedded资源存储到System.Web.Mvc程序集中,并且提取的方法是内部密封的内部类( System.Web.Mvc.ClientDataTypeModelValidatorProvider+NumericModelValidator.MakeErrorString )的私有静态方法。 就好像在微软编码的人隐藏了一个绝密:-)

您可以看看下面的博客文章 ,其中描述了一个可能的解决scheme。 您基本上需要用自定义的replace现有的ClientDataTypeModelValidatorProvider 。

如果你不喜欢你需要做的核心代码,你也可以用一个stringreplace视图模型中的这个整数值,并在其上有一个自定义的validation属性,它将执行parsing并提供一个自定义的错误信息甚至可以本地化)。

您可以在渲染字段时通过自己提供data-val-number属性来覆盖消息。 这覆盖了默认的消息。 这至less与MVC 4一起工作。

@ Html.EditorFor(model => model.MyNumberField,new {data_val_number =“Supply an integer,dude!”))

请记住,您必须在Razor的属性名称中使用下划线来接受您的属性。

你必须做的是:

Global.asax Application_Start()中添加下面的代码:

  ClientDataTypeModelValidatorProvider.ResourceClassKey = "Messages"; DefaultModelBinder.ResourceClassKey = "Messages"; 

在VS中右键单击ASP.NET MVC项目。 selectAdd => Add ASP.NET Folder => App_GlobalResources

在该文件夹中添加名为Messages.resx.resx文件。

.resx文件中添加这些string资源:

 FieldMustBeDate The field {0} must be a date. FieldMustBeNumeric The field {0} must be a number. PropertyValueInvalid The value '{0}' is not valid for {1}. PropertyValueRequired A value is required. 

根据需要更改FieldMustBeNumeric值… 🙂

你完成了。


检查这个职位的更多细节:

本地化ASP.NET MVC和WebForms中的默认错误消息

作为替代方法,我应用了RegularExpression属性来捕获无效条目,并在那里设置我的消息:

 [RegularExpression(@"[0-9]*$", ErrorMessage = "Please enter a valid number ")] 

这有些诡异,但这似乎比其他解决scheme的复杂性要好,至less在我的特殊情况下。

编辑:这在MVC3中运行良好,但似乎有可能是MVC4 +更好的解决scheme。

从这本书我有MVC 3。 所有你需要做的是这样的:

 public class ClientNumberValidatorProvider : ClientDataTypeModelValidatorProvider { public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context) { bool isNumericField = base.GetValidators(metadata, context).Any(); if (isNumericField) yield return new ClientSideNumberValidator(metadata, context); } } public class ClientSideNumberValidator : ModelValidator { public ClientSideNumberValidator(ModelMetadata metadata, ControllerContext controllerContext) : base(metadata, controllerContext) { } public override IEnumerable<ModelValidationResult> Validate(object container) { yield break; // Do nothing for server-side validation } public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { yield return new ModelClientValidationRule { ValidationType = "number", ErrorMessage = string.Format(CultureInfo.CurrentCulture, ValidationMessages.MustBeNumber, Metadata.GetDisplayName()) }; } } protected void Application_Start() { // Leave the rest of this method unchanged var existingProvider = ModelValidatorProviders.Providers .Single(x => x is ClientDataTypeModelValidatorProvider); ModelValidatorProviders.Providers.Remove(existingProvider); ModelValidatorProviders.Providers.Add(new ClientNumberValidatorProvider()); } 

注意ErrorMessage是如何产生的,你指定了当前的文化,本地化的消息是从ValidationMessages(这里是文化细节).resx资源文件中提取的。 如果你不需要,只需用你自己的信息来replace它。

这里是另一个解决scheme,它改变了消息客户端而不改变MVC3源。 在这个博客文章的全部细节:

https://greenicicle.wordpress.com/2011/02/28/fixing-non-localizable-validation-messages-with-javascript/

总之,你需要做的是在加载jQueryvalidation加上适当的本地化文件后包含以下脚本。

 (function ($) { // Walk through the adapters that connect unobstrusive validation to jQuery.validate. // Look for all adapters that perform number validation $.each($.validator.unobtrusive.adapters, function () { if (this.name === "number") { // Get the method called by the adapter, and replace it with one // that changes the message to the jQuery.validate default message // that can be globalized. If that string contains a {0} placeholder, // it is replaced by the field name. var baseAdapt = this.adapt; this.adapt = function (options) { var fieldName = new RegExp("The field (.+) must be a number").exec(options.message)[1]; options.message = $.validator.format($.validator.messages.number, fieldName); baseAdapt(options); }; } }); } (jQuery)); 

您可以将ClientDataTypeModelValidatorProvider类的ResourceKey设置为包含FieldMustBeNumeric项的全局资源的名称,以用您的自定义消息来replacenumber的mvcvalidation错误消息。 datevalidation错误消息的关键是FieldMustBeDate。

 ClientDataTypeModelValidatorProvider.ResourceKey="MyResources"; // MyResource is my global resource 

这是纯js中的另一个解决scheme,如果您想为每个项目指定全局消息而不是自定义消息,则可以使用这个解决scheme

关键是validation消息是使用jquery.validation.unobtrusive.js在每个元素上使用data-val-xxx属性来设置的,所以你只需要在库使用之前replace这些消息,这有点脏但我只是想完成工作,而且速度很快,所以在这里进行数字typesvalidation:

  $('[data-val-number]').each(function () { var el = $(this); var orig = el.data('val-number'); var fieldName = orig.replace('The field ', ''); fieldName = fieldName.replace(' must be a number.', ''); el.attr('data-val-number', fieldName + ' باید عددی باشد') }); 

好的一点是它不需要编译,而且以后可以很容易地扩展它,虽然不健壮,但速度很快。

检查了这一点:

在ASP.NET MVC 3validation完整指南 – 第2部分

文章的主要部分如下(复制粘贴)。

有四个不同的部分来创build一个function齐全的自定义validation程序,可以在客户端和服务器上运行。 首先我们inheritanceValidationAttribute并添加我们的服务器端validation逻辑。 接下来,我们在我们的属性上实现IClientValidatable ,以允许将HTML5 data-*属性传递给客户端。 第三,我们编写一个自定义的JavaScript函数,在客户端执行validation。 最后,我们创build一个适配器将HTML5属性转换为我们自定义函数可以理解的格式。 虽然这听起来像很多工作,但一旦你开始,你会发现它相对简单。

子类化ValidationAttribute

在这个例子中,我们将编写一个NotEqualTovalidation器,它只是检查一个属性的值是否与另一个属性的值不相等。

 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class NotEqualToAttribute : ValidationAttribute { private const string DefaultErrorMessage = "{0} cannot be the same as {1}."; public string OtherProperty { get; private set; } public NotEqualToAttribute(string otherProperty) : base(DefaultErrorMessage) { if (string.IsNullOrEmpty(otherProperty)) { throw new ArgumentNullException("otherProperty"); } OtherProperty = otherProperty; } public override string FormatErrorMessage(string name) { return string.Format(ErrorMessageString, name, OtherProperty); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { var otherProperty = validationContext.ObjectInstance.GetType() .GetProperty(OtherProperty); var otherPropertyValue = otherProperty .GetValue(validationContext.ObjectInstance, null); if (value.Equals(otherPropertyValue)) { return new ValidationResult( FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } } 

将新属性添加到R​​egisterModel的password属性并运行该应用程序。

 [Required] [DataType(DataType.Password)] [Display(Name = "Password")] [NotEqualTo("UserName")] public string Password { get; set; } ... 

实现IClientValidatable

ASP.NET MVC 2有一个添加客户端validation的机制,但不是很漂亮。 幸运的是,在MVC 3中,事情已经改进了,现在这个过程已经相当平凡了,幸好不需要像以前的版本那样改变Global.asax

第一步是让您的自定义validation属性实现IClientValidatable。 这是一个简单的方法界面:

 public IEnumerable<ModelClientValidationRule> GetClientValidationRules( ModelMetadata metadata, ControllerContext context) { var clientValidationRule = new ModelClientValidationRule() { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "notequalto" }; clientValidationRule.ValidationParameters.Add("otherproperty", OtherProperty); return new[] { clientValidationRule }; } 

如果现在运行应用程序并查看源代码,则会看到密码inputhtml现在包含您的notequalto数据属性:

 <div class="editor-field"> <input data-val="true" data-val-notequalto="Password cannot be the same as UserName." data-val-notequalto-otherproperty="UserName" data-val-regex="Weak password detected." data-val-regex-pattern="^(?!password$)(?!12345$).*" data-val-required="The Password field is required." id="Password" name="Password" type="password" /> <span class="hint">Enter your password here</span> <span class="field-validation-valid" data-valmsg-for="Password" data-valmsg-replace="true"></span> </div> 

创build一个自定义的jQueryvalidation函数

所有这些代码最好放在一个单独的JavaScript文件中。

 (function ($) { $.validator.addMethod("notequalto", function (value, element, params) { if (!this.optional(element)) { var otherProp = $('#' + params); return (otherProp.val() != } return true; }); $.validator.unobtrusive.adapters.addSingleVal("notequalto", "otherproperty"); }(jQuery)); 

根据您的validation要求,您可能会发现jquery.validate库已经有了validation本身所需的代码。 jquery.validate中有很多validation器没有实现或映射到数据注释,所以如果这些满足您的需要,那么您需要用javascript编写一个适配器,甚至是一个内置适配器的调用,它可以尽可能less一条线。 看看里面的jquery.validate.js找出什么是可用的。

使用现有的jquery.validate.unobtrusive适配器

适配器的工作是读取表单元素上的HTML5 data-*属性,并将这些数据转换为jquery.validate和您的自定义validation函数可以理解的forms。 你不需要自己做所有的工作,在很多情况下,你可以调用一个内置的适配器。 jquery.validate.unobtrusive声明了三个内置的适配器,可以在大多数情况下使用。 这些是:

 jQuery.validator.unobtrusive.adapters.addBool - used when your validator does not need any additional data. jQuery.validator.unobtrusive.adapters.addSingleVal - used when your validator takes in one piece of additional data. jQuery.validator.unobtrusive.adapters.addMinMax - used when your validator deals with minimum and maximum values such as range or string length. 

如果您的validation器不适合这些类别之一,则需要使用jQuery.validator.unobtrusive.adapters.add方法编写自己的适配器。 这听起来并不困难,我们将在后面的文章中看到一个例子。

我们使用addSingleVal方法,传入适配器的名称和我们想传递的单个值的名称。 如果validation函数的名称与适配器不同,则可以传入第三个参数( ruleName ):

 jQuery.validator.unobtrusive.adapters.addSingleVal("notequalto", "otherproperty", "mynotequaltofunction"); 

在这一点上,我们的自定义validation器是完整的。

为了更好的理解,请参考文章本身 ,它提供了更多的描述和更复杂的例子。

HTH。

我刚刚做了这个,然后使用正则expression式:

 $(document).ready(function () { $.validator.methods.number = function (e) { return true; }; }); [RegularExpression(@"^[0-9\.]*$", ErrorMessage = "Invalid Amount")] public decimal? Amount { get; set; } 

或者你可以简单地做到这一点。

 @Html.ValidationMessageFor(m => m.PercentChange, "Custom Message: Input value must be a number"), new { @style = "display:none" }) 

希望这可以帮助。

我在KendoGrid中有这个问题,我在视图的末尾使用脚本覆盖data-val-number:

 @(Html.Kendo().Grid<Test.ViewModel>(Model) .Name("listado") ... .Columns(columns => { columns.Bound("idElementColumn").Filterable(false); ... } 

至less在最后,我认为:

 <script type="text/javascript"> $("#listado").on("click", function (e) { $(".k-grid #idElementColumn").attr('data-val-number', 'Ingrese un número.'); }); </script>