如何在@Html帮助程序生成的MVC中更改“data-val-number”消息验证

时间:2011-01-28 12:38:09

标签: asp.net-mvc asp.net-mvc-3 localization unobtrusive-validation 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错误消息,因为PercentChangeInteger。我正在寻找这样一个属性来改变它,range或任何相关的不起作用 我知道有可能编辑不显眼的js文件本身或在客户端覆盖它。我想像服务器端的其他人一样更改data-val-number的错误消息。

14 个答案:

答案 0 :(得分:72)

您可以在渲染字段时通过自己提供 data-val-number 属性来覆盖该消息。这会覆盖默认消息。这至少适用于MVC 4。

  

@ Html.EditorFor(model =&gt; model.MyNumberField,new {data_val_number =“提供一个整数,伙计!”})

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

答案 1 :(得分:49)

你要做的是:

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

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

右键单击VS中的ASP.NET MVC项目。选择Add => Add ASP.NET Folder => App_GlobalResources

在该文件夹中添加名为.resx的{​​{1}}文件。

Messages.resx文件中添加这些字符串资源:

.resx

根据需要更改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. 值...:)

你已经完成了。


查看此帖子了解更多详情:

Localizing Default Error Messages in ASP.NET MVC and WebForms

答案 2 :(得分:37)

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

您可以查看以下blog post,其中介绍了可能的解决方案。您基本上需要使用自定义的ClientDataTypeModelValidatorProvider替换现有的{{3}}。

如果您不喜欢需要执行的核心编码,您还可以使用字符串替换视图模型中的此整数值,并在其上具有自定义验证属性,该属性将执行解析并提供自定义错误消息(甚至可以本地化)。

答案 3 :(得分:22)

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

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

这有点像黑客,但这似乎比其他解决方案的复杂性更好,至少在我的特殊情况下。

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

答案 4 :(得分:11)

我从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资源文件中提取本地化消息。如果您不需要,只需将其替换为您自己的消息。

答案 5 :(得分:7)

这是另一个解决方案,它在没有更改MVC3源的情况下更改了消息客户端。此博客文章中的完整详细信息:

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

简而言之,您需要做的是在加载jQuery验证和appropriate localisation file之后包含以下脚本。

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

答案 6 :(得分:4)

您可以将ClientDataTypeModelValidatorProvider类的ResourceKey设置为包含FieldMustBeNumeric键的全局资源的名称,以使用您的自定义消息替换数字的mvc验证错误消息。此日期验证错误消息的关键还有FieldMustBeDate。

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

答案 7 :(得分:3)

以下是纯js中的另一种解决方案,如果您想要全局指定消息而不是每个项目的自定义消息,则可以使用。

关键是验证消息是使用jquery.validation.unobtrusive.js使用每个元素的data-val-xxx属性设置的,所以你要做的就是在库使用之前替换这些消息,它有点脏,但我只是想完成工作并快速完成,所以这里是数字类型验证:

    $('[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 + ' باید عددی باشد')
});

好处是它不需要编译,你可以在以后轻松扩展,但不是很健壮,但速度很快。

答案 8 :(得分:2)

检查一下:

The Complete Guide To Validation In ASP.NET MVC 3 - Part 2

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

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

子类化ValidationAttribute

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

[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有一种添加客户端验证的机制,但它不是很漂亮。值得庆幸的是,在MVC 3中,事情已经有所改进,现在这个过程相当简单,谢天谢地涉及像以前版本一样更改Global.asax

第一步是使用自定义验证属性来实现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 };
}

如果您现在运行应用程序并查看源代码,您会看到密码输入html现在包含您的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>

创建自定义jQuery验证功能

所有这些代码最好放在一个单独的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));

根据您的验证要求,您可能会发现jquery.validate库已经拥有验证本身所需的代码。 jquery.validate中有许多验证器尚未实现或映射到数据注释,所以如果满足您的需求,那么您需要在javascript中编写的所有内容都是适配器甚至是对内置适配器的调用只需一条线。看一下 jquery.validate.js ,找出可用的内容。

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

适配器的工作是读取表单元素上的HTML5 data-*属性,并将此数据转换为jquery.validate和您的自定义验证函数可以理解的表单。您不需要自己完成所有工作,在许多情况下,您可以调用内置适配器。 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.

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

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

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

此时,我们的自定义验证器已完成。

为了更好地理解,请参阅article itself,它提供了更多描述和更复杂的示例。

HTH。

答案 9 :(得分:1)

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

$(document).ready(function () {
    $.validator.methods.number = function (e) {
        return true;
    };
});


[RegularExpression(@"^[0-9\.]*$", ErrorMessage = "Invalid Amount")]
public decimal? Amount { get; set; }

答案 10 :(得分:1)

或者你可以简单地这样做。

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

希望这会有所帮助。

答案 11 :(得分:0)

我在KendoGrid中遇到此问题,我在视图的END处使用脚本来覆盖data-val-number:

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

至少,在View I的最后我说:

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

答案 12 :(得分:0)

我将此视为我的观点

@Html.DropDownListFor(m => m.BenefNamePos, Model.Options, new { onchange = "changePosition(this);", @class="form-control", data_val_number = "This is my custom message" })

答案 13 :(得分:0)

一种简单的方法是,在ViewModel上使用数据注释更改消息:

[Required(ErrorMessage ="الزامی")]
[StringLength(maximumLength:50,MinimumLength =2)]
[Display(Name = "نام")]
public string FirstName { get; set; }