Cách thay đổi xác thực thông báo 'data-val-number' trong MVC khi nó được tạo bởi trình trợ giúp @Html


76

Giả sử mô hình này:

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

và chế độ xem:

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

sẽ tiếp tục html này:

   <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" />

Tôi muốn tùy chỉnh thông data-val-numberbáo lỗi mà tôi đoán đã tạo ra vì PercentChangelà một Integer. Tôi đang tìm kiếm một thuộc tính như vậy để thay đổi nó, rangehoặc bất cứ điều gì liên quan không hoạt động.
Tôi biết có một cơ hội trong việc chỉnh sửa tệp js không phô trương của chính nó hoặc ghi đè nó ở phía máy khách. Tôi muốn thay đổi data-val-numberthông báo lỗi của giống như những người khác ở phía máy chủ.


Tôi đã sử dụng Griffin MVC contrib dự án để bản địa hoá các văn bản xác nhận không có thuộc tính xấu xí
Eduardo Molteni

Câu trả lời:


39

Điều này sẽ không dễ dàng. Thông báo mặc định được lưu trữ dưới dạng tài nguyên nhúng vào hợp System.Web.Mvcngữ và phương thức đang tìm nạp là phương thức tĩnh riêng của một lớp bên trong được niêm phong bên trong ( System.Web.Mvc.ClientDataTypeModelValidatorProvider+NumericModelValidator.MakeErrorString). Cứ như thể anh chàng viết mã của Microsoft này đang che giấu một bí mật hàng đầu :-)

Bạn có thể xem bài đăng trên blog sau đây mô tả một giải pháp khả thi. Về cơ bản, bạn cần thay thế ClientDataTypeModelValidatorProvider hiện có bằng một tùy chỉnh.

Nếu bạn không thích mã hóa khó mà bạn sẽ cần thực hiện, bạn cũng có thể thay thế giá trị số nguyên này bên trong mô hình chế độ xem của mình bằng một chuỗi và có thuộc tính xác thực tùy chỉnh trên đó sẽ thực hiện phân tích cú pháp và cung cấp thông báo lỗi tùy chỉnh ( thậm chí có thể được bản địa hóa).


3
wow, bạn phải rất giỏi trong những điều bí mật này :). mã rất khó. Tôi không hiểu tại sao họ lại làm khó thế này! Tôi đã rất vui khi họ sửa những thứ này trong MVC3 RTM nhưng họ không làm vậy. Tôi đặt nó vào bộ điều khiển của mình chỉ để kiểm tra xem nó có hoạt động không. và cảm ơn nó hoạt động như một sự quyến rũ. nhưng tôi nên đặt removethứ này ở đâu? trong của tôi global.asax? vậy có ổn không?
GtEx

2
@GtEx, có Providers.RemoveProviders.Addnên được đặt trong Application_Startphương thức Global.asax của bạn.
Darin Dimitrov

Có ai có thể làm điều gì đó tương tự như thế này, nhưng có thể tạo thông báo dựa trên các giá trị khác từ đối tượng mà số đó đang được xác thực không? ví dụ: nếu đối tượng của tôi có "Lời nhắc" và "giá trị", thông báo của tôi sẽ cho biết "{Lời nhắc} phải là một số." Hoặc, tôi phải thực hiện xác nhận đối tượng cho điều đó?
Richard B

8
Nhìn vào mã nguồn của MVC 4, có vẻ như nó đã được sửa cho phép chúng tôi chỉ định ResourceClassKey aspnetwebstack.codeplex.com/SourceControl/changeset/view/…
MartinHN

3
Đúng. Thay thế ResourceClassKey và sử dụng tên FieldMustBeNumeric đã hoạt động trong trường hợp này. Đối với các lỗi bắt buộc và không hợp lệ, hãy sử dụng cách tiếp cận khác này cũng được Darin Dimitrov phản đối stackoverflow.com/questions/12545176/…
Eduardo

77

Bạn có thể ghi đè thông báo bằng cách tự cung cấp thuộc tính data-val-number khi hiển thị trường. Điều này ghi đè thông báo mặc định. Điều này hoạt động ít nhất với MVC 4.

@ Html.EditorFor (model => model.MyNumberField, new {data_val_number = "Cung cấp một số nguyên, anh bạn!"})

Hãy nhớ rằng bạn phải sử dụng dấu gạch dưới trong tên thuộc tính để Razor chấp nhận thuộc tính của bạn.


Tôi không biết làm thế nào bạn làm cho nó hoạt động. Trong thuộc tính MVC4-app của tôi được thêm vào theo cách này bị bỏ qua.
blazkovicz

Điều này đã làm việc cho tôi, mặc dù trong trường hợp của tôi, tôi chỉ muốn tắt nó đi. data_val = "false" đã đủ.
James

4
Tôi không thể thấy điều này sẽ hoạt động như thế nào. Nếu đây là một htmlAttributesđối tượng mới , nó có thể hoạt động, nhưng nó là một additionalViewDatađối tượng, vì vậy bạn chỉ nhận được một thuộc tính bổ sung được gọi data_val_number.
Sprintstar

3
@HenningJ Làm việc tuyệt vời cho tôi, cảm ơn vì đã tiết kiệm cho tôi rất nhiều thời gian :)
David Work vào

3
Tôi đồng ý với @Sprintstar. Nó không làm việc cho tôi nhưng @Html.EditorFor(model => model.age, new { htmlAttributes = new { @class = "form-control", data_val_required = "Field required"} })đã làm.
dùng1

52

Những gì bạn phải làm là:

Thêm mã sau vào bên Application_Start()trong Global.asax:

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

Nhấp chuột phải vào dự án ASP.NET MVC của bạn trong VS. Lựa chọnAdd => Add ASP.NET Folder => App_GlobalResources .

Thêm một .resxtệp có tênMessages.resx trong thư mục đó.

Thêm các tài nguyên chuỗi này vào .resxtệp:

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.

Thay đổi FieldMustBeNumericgiá trị như bạn muốn ... :)

Bạn đã hoàn tất.


Kiểm tra bài đăng này để biết thêm chi tiết:

Bản địa hóa thông báo lỗi mặc định trong ASP.NET MVC và WebForms


Tôi không nhận được bản dịch cho PropertyValueInvalid, chỉ có văn bản mặc định ... Bạn có ý kiến ​​gì không?
user1073075

4
Mặc dù @DarinDimitrov có một giải pháp hợp lệ, nhưng đối với tôi, đây phải là câu trả lời được chấp nhận, vì nó sử dụng cơ chế có thể mở rộng tích hợp thay vì sao chép toàn bộ lớp .Net và thay đổi nó, điều này ít có thể bảo trì hơn nhiều
tsemer

5
Đây thực sự là câu trả lời tốt nhất cho câu hỏi này.
Nick Coad

2
@Nick Coad. Vâng, đó là câu trả lời tốt nhất - và không có câu trả lời rườm rà nào cho câu hỏi này. Tôi có thể xác nhận nó hoạt động trong MVC 4 và MVC 5
netfed

23

Một cách khác để giải quyết vấn đề này, tôi đã áp dụng thuộc tính RegularExpression để bắt mục nhập không hợp lệ và đặt thông báo của tôi ở đó:

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

Đây hơi là một vụ hack nhưng điều này có vẻ thích hợp hơn so với sự phức tạp mà các giải pháp khác đã trình bày, ít nhất là trong tình huống cụ thể của tôi.

CHỈNH SỬA: Điều này hoạt động tốt trong MVC3 nhưng có vẻ như có thể có các giải pháp tốt hơn cho MVC4 +.


1
Tôi vẫn thích giải pháp đầu tiên hơn, gọn gàng hơn nhiều. chỉ một dòng mã trong global.asax. vấn đề với điều này là bạn phải thêm thuộc tính này vào mọi thuộc tính số nguyên trong dự án của bạn và nó sử dụng biểu thức chính quy, điều này khiến tôi không thoải mái với quá trình chỉ mất 0,0001 giây để regEx nó;)
GtEx 2/11/11

2
Không có tranh cãi rằng nó là một chút hack. Biện pháp bảo vệ duy nhất của tôi rằng sẽ cực kỳ dễ dàng để ghi đè bất kỳ thông báo lỗi nào trong khuôn khổ.
Matthew Nichols

Chà, cách đúng để làm điều đó là làm cho nó có thể ghi đè một cách dễ dàng ... nhưng vì chúng tôi không thể làm điều đó, tôi rất vui vì bạn thấy suy nghĩ của tôi hữu ích.
Matthew Nichols

Có vẻ như tôi không cần đến đô la, có lẽ ^ và $ là ẩn sau đó.
Anders Lindén

Tôi chỉ biết OP là một số nguyên nhưng điều này sẽ nhanh chóng vượt khỏi tầm tay nếu bạn xem xét các số thập phân và i18n?
phuzi

11

Từ cuốn sách này trên MVC 3 mà tôi có. Tất cả những gì bạn phải làm là:

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

Lưu ý cách ErrorMessage được tạo ra, bạn chỉ định văn hóa hiện tại và thông báo bản địa hóa được trích xuất từ ​​tệp tài nguyên .resx ValidationMessages (ở đây là văn hóa cụ thể). Nếu bạn không cần điều đó, chỉ cần thay thế nó bằng thông điệp của riêng bạn.


Nghe có vẻ phức tạp hơn nhiều so với giải pháp tôi đã chọn. chưa kể chúng tôi không có yield returntrong vb.net, mặc dù có một công việc xung quanh. Tôi vẫn không nhận được những lợi thế của giải pháp này.
GtEx

Tôi thực sự thích giải pháp này. Một câu hỏi: chúng tôi đang thay thế nhà cung cấp hiện tại bằng một nhà cung cấp mới. Điều gì sẽ xảy ra nếu nhà cung cấp hiện tại đã từng làm nhiều việc hơn là chỉ xác thực này? Có đảm bảo rằng bằng cách xóa nó, chúng tôi không phá vỡ bất kỳ chức năng nào khác không?
Alex

7

Đây là một giải pháp khác thay đổi phía máy khách thông báo mà không thay đổi nguồn MVC3. Chi tiết đầy đủ trong bài đăng blog này:

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

Tóm lại, những gì bạn cần làm là bao gồm tập lệnh sau sau khi xác thực jQuery được tải cùng với tệp bản địa hóa thích hợp .

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

Cảm ơn Phil, (+1 cho) thật tốt khi biết. Nhưng cá nhân tôi muốn thay đổi MVC3 trong vấn đề cụ thể này. Tôi hy vọng họ đưa bản sửa lỗi này vào bản phát hành tiếp theo.
GtEx

4

Bạn có thể đặt ResourceKey của lớp ClientDataTypeModelValidatorProvider thành tên của tài nguyên chung có chứa khóa FieldMustBeNumeric để thay thế thông báo lỗi xác thực mvc của số bằng thông báo tùy chỉnh của bạn. Ngoài ra, thông báo lỗi xác thực ngày quan trọng là FieldMustBeDate.

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

1
Thật tuyệt vời, điều này thực sự hoạt động! Đó là ResourceClassKeymặc dù, khôngResourceKey
Vincent SELS

3

Đây là một giải pháp khác trong js thuần túy hoạt động nếu bạn muốn chỉ định thông báo trên toàn cầu chứ không phải thông báo tùy chỉnh cho từng mục.

Điều quan trọng là các thông báo xác thực được đặt bằng cách sử jquery.validation.unobtrusive.jsdụng data-val-xxxthuộc tính trên mỗi phần tử, vì vậy tất cả những gì bạn phải làm là thay thế các thông báo đó trước khi thư viện sử dụng chúng, hơi bẩn nhưng tôi chỉ muốn hoàn thành công việc một cách nhanh chóng, vì vậy ở đây nó dùng để xác thực kiểu số:

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

điều tốt là nó không yêu cầu biên dịch và bạn có thể mở rộng nó một cách dễ dàng sau đó, mặc dù không mạnh nhưng nhanh.


2

Kiểm tra cái này quá:

Hướng dẫn hoàn chỉnh để xác thực trong ASP.NET MVC 3 - Phần 2

Các phần chính của bài viết theo sau (copy-paste).

Có bốn phần riêng biệt để tạo trình xác thực tùy chỉnh đầy đủ chức năng hoạt động trên cả máy khách và máy chủ. Đầu tiên, chúng tôi phân lớp ValidationAttributevà thêm logic xác thực phía máy chủ của chúng tôi. Tiếp theo, chúng tôi triển khai IClientValidatabletrên thuộc tính của mình để cho phép các data-*thuộc tính HTML5 được chuyển đến máy khách. Thứ ba, chúng tôi viết một hàm JavaScript tùy chỉnh để thực hiện xác thực trên máy khách. Cuối cùng, chúng tôi tạo một bộ điều hợp để chuyển đổi các thuộc tính HTML5 thành một định dạng mà chức năng tùy chỉnh của chúng tôi có thể hiểu được. Mặc dù điều này nghe có vẻ như rất nhiều công việc, nhưng một khi bạn bắt đầu, bạn sẽ thấy nó tương đối đơn giản.

Xác thực lớp con

Trong ví dụ này, chúng ta sẽ viết một trình xác thực NotEqualTo chỉ đơn giản là kiểm tra xem giá trị của một thuộc tính không bằng giá trị của một thuộc tính khác.

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

Thêm thuộc tính mới vào thuộc tính mật khẩu của RegisterModel và chạy ứng dụng.

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

Triển khai IClientValidatable

ASP.NET MVC 2 có một cơ chế để thêm xác thực phía máy khách nhưng nó không đẹp lắm. Rất may trong MVC 3, mọi thứ đã được cải thiện và quá trình này hiện khá đơn giản và rất may không liên quan đến việc thay đổi Global.asaxnhư trong phiên bản trước.

Bước đầu tiên là để thuộc tính xác thực tùy chỉnh của bạn triển khai IClientValidatable. Đây là một giao diện đơn giản, một phương thức:

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

Nếu bạn chạy ứng dụng ngay bây giờ và xem mã nguồn, bạn sẽ thấy html nhập mật khẩu bây giờ chứa các notequaltothuộc tính dữ liệu của bạn :

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

Tạo một hàm xác thực jQuery tùy chỉnh

Tất cả mã này tốt nhất nên được đặt trong một tệp JavaScript riêng.

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

Tùy thuộc vào yêu cầu xác thực của bạn, bạn có thể thấy rằng thư viện jquery.validate đã có mã mà bạn cần để xác thực chính nó. Có rất nhiều trình xác thực trong jquery.validate chưa được triển khai hoặc ánh xạ tới các chú thích dữ liệu, vì vậy nếu chúng đáp ứng nhu cầu của bạn, thì tất cả những gì bạn cần viết trong javascript là một bộ điều hợp hoặc thậm chí là một lệnh gọi đến một bộ điều hợp tích hợp sẵn. nhỏ như một dòng duy nhất. Hãy nhìn vào bên trong jquery.validate.js để tìm hiểu những gì có sẵn.

Sử dụng bộ điều hợp jquery.validate.unobtruser hiện có

Công việc của bộ điều hợp là đọc các data-*thuộc tính HTML5 trên phần tử biểu mẫu của bạn và chuyển đổi dữ liệu này thành một biểu mẫu mà jquery.validate và chức năng xác thực tùy chỉnh của bạn có thể hiểu được. Tuy nhiên, bạn không bắt buộc phải tự mình làm tất cả công việc và trong nhiều trường hợp, bạn có thể gọi một bộ điều hợp tích hợp sẵn. jquery.validate.unobtrusing khai báo ba bộ điều hợp tích hợp có thể được sử dụng trong phần lớn các tình huống. Đó là:

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.

Nếu trình xác thực của bạn không phù hợp với một trong các danh mục này, bạn bắt buộc phải viết bộ điều hợp của riêng mình bằng jQuery.validator.unobtrusive.adapters.addphương pháp này. Điều này không quá khó khăn và chúng ta sẽ xem một ví dụ sau trong bài viết.

Chúng tôi sử dụng addSingleValphương thức, truyền vào tên của bộ điều hợp và tên của giá trị duy nhất mà chúng tôi muốn chuyển. Nếu tên của hàm xác thực khác với bộ điều hợp, bạn có thể chuyển vào tham số thứ ba ( ruleName):

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

Tại thời điểm này, trình xác thực tùy chỉnh của chúng tôi đã hoàn tất.

Để hiểu rõ hơn, hãy tham khảo bài viết trình bày nhiều mô tả hơn và một ví dụ phức tạp hơn.

HTH.


1

Tôi chỉ làm điều này và sau đó sử dụng biểu thức regex:

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


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

1

Hoặc bạn có thể đơn giản làm điều này.

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

Hi vọng điêu nay co ich.


1

Tôi thực hiện điều này dựa trên quan điểm của tôi

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

0

Tôi gặp sự cố này trong KendoGrid, tôi sử dụng một tập lệnh ở END of View để ghi đè data-val-number:

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

Và ít nhất, ở phần cuối của Chế độ xem, tôi đã đặt:

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

0

một phương pháp đơn giản là sử dụng thông báo thay đổi chú thích dữ liệu trên ViewModel:

[Required(ErrorMessage ="الزامی")]
[StringLength(maximumLength:50,MinimumLength =2)]
[Display(Name = "نام")]
public string FirstName { get; set; }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.