Як змінити перевірку повідомлення "data-val-number" у MVC, коли воно генерується помічником @Html


76

Припустимо цю модель:

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повідомлення про помилку, як і інші на стороні сервера.


Я використовував проект Griffin MVC Contrib для локалізації текстів перевірки без потворних атрибутів
Едуардо Молтені,

Відповіді:


39

Це буде непросто. Повідомлення за замовчуванням зберігається як вбудований ресурс у System.Web.Mvcзбірці, а метод, що отримується, є приватним статичним методом внутрішнього закритого внутрішнього класу ( System.Web.Mvc.ClientDataTypeModelValidatorProvider+NumericModelValidator.MakeErrorString). Це наче хлопець із Microsoft, що кодує це, приховував цілком секрет :-)

Ви можете поглянути на наступну публікацію в блозі, де описується можливе рішення. В основному вам потрібно замінити існуючий ClientDataTypeModelValidatorProvider на власний.

Якщо вам не подобається жорстке кодування, яке вам потрібно буде зробити, ви також можете замінити це ціле значення всередині вашої моделі подання на рядок і мати на ньому власний атрибут перевірки, який буде виконувати синтаксичний аналіз та надавати власне повідомлення про помилку (яке навіть може бути локалізовано).


3
вау, ви, мабуть, дуже добре вмієте ці секретні речі :). дуже жорсткий код. Я не розумію, чому вони це ускладнюють! Я якось стрибав, що вони виправляють ці речі в MVC3 RTM, але цього не робили. Я поміщаю його у свій контролер, щоб просто перевірити, чи він працює. і дякую, це працює як шарм. але куди мені покласти цю removeріч? в моєму global.asax? це нормально тоді?
GtEx

2
@GtEx, так Providers.Removeі Providers.Addслід розміщувати у Application_Startметоді вашого Global.asax.
Дарін Димитров

Хтось зміг зробити щось подібне до цього, але зміг створити повідомлення на основі інших значень з об’єкта, на якому перевіряється число? наприклад, якби мій об'єкт мав "Підказка" та "значення", у моєму повідомленні було б сказано "{Підказка} має бути числом". Або мені для цього потрібно зробити перевірку об’єкта?
Richard B

8
Заглядаючи у вихідний код MVC 4, схоже, це виправлено, що дозволяє нам вказати наш власний ResourceClassKey aspnetwebstack.codeplex.com/SourceControl/changeset/view/…
MartinHN

3
Так. Заміна ResourceClassKey та використання імені FieldMustBeNumeric спрацювали в цьому випадку. Для обов’язкових та недійсних помилок використовуйте цей інший підхід, також запропонований Даріном Димитровим stackoverflow.com/questions/12545176/…
Едуардо

77

Ви можете замінити повідомлення, надавши атрибут data-val-number самостійно при отрисуванні поля. Це замінює повідомлення за замовчуванням. Це працює принаймні з MVC 4.

@ Html.EditorFor (model => model.MyNumberField, new {data_val_number = "Введіть ціле число, чувак!"})

Пам’ятайте, що для того, щоб Razor прийняв ваш атрибут, у назві атрибута потрібно використовувати підкреслення.


Не знаю, як ти змусив це працювати. У моєму атрибуті програми MVC4 доданий таким чином ігнорується.
blazkovicz

Це спрацювало для мене, хоча у моєму випадку я просто хотів його вимкнути. data_val = "false" вистачає.
Джеймс

4
Я не можу зрозуміти, як це могло би працювати. Якби це був новий htmlAttributesоб’єкт, він міг би працювати, але це additionalViewDataоб’єкт, тож ви просто отримали додатковий атрибут data_val_number.
Спринцтар

3
@HenningJ чудово працює для мене, дякую, що заощадили купу купу часу :)
David Work

3
Я згоден з @Sprintstar. Це не спрацювало у мене, але так @Html.EditorFor(model => model.age, new { htmlAttributes = new { @class = "form-control", data_val_required = "Field required"} })і було.
user1

52

Що вам потрібно зробити, це:

Додайте такий код всередину Application_Start()в Global.asax:

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

Клацніть правою кнопкою миші ваш проект ASP.NET MVC у VS. Виберіть Add => Add ASP.NET Folder => App_GlobalResources.

Додайте .resxфайл, який називається 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.

Змінюйте FieldMustBeNumericзначення як завгодно ... :)

Ви закінчили.


Перегляньте цю публікацію, щоб дізнатися більше:

Локалізація повідомлень про помилки за замовчуванням у ASP.NET MVC та WebForms


Я не отримую переклад для PropertyValueInvalid, лише текст за замовчуванням ... Будь-яка ідея?
user1073075

4
Хоча @DarinDimitrov має дійсне рішення, для мене це має бути прийнятою відповіддю, оскільки він використовує вбудований розширюваний механізм замість копіювання цілого класу .Net та його зміни, що набагато менш ремонтопридатне
цемер,

5
Це справді найкраща відповідь на це питання.
Нік Коад,

2
@ Нік Коад. Так, це найкраще - і ніяких надмірних відповідей на це питання. Я можу підтвердити, що це працює у MVC 4 та MVC 5
передано мережу

23

Як альтернативний спосіб обійти це, я застосував атрибут RegularExpression, щоб зловити невірний запис і встановити там своє повідомлення:

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

Це трохи злом, але це здавалося кращим, ніж складність інших представлених рішень, принаймні в моїй конкретній ситуації.

EDIT: Це добре працювало в MVC3, але, здається, цілком можуть бути кращі рішення для MVC4 +.


1
все-таки я віддаю перевагу першому рішенню, набагато акуратніше. лише один рядок коду в global.asax. проблема в тому, що ви повинні додати цей атрибут до кожного окремого цілого числа властивостей у вашому проекті, і він використовує регулярний вираз, що робить мене некомфортним із процесом, який вимагає лише 0,0001 сек, щоб його виправити;)
GtEx

2
Немає аргументів, що це трохи хак. Єдиний мій захист, що замінити будь-яке повідомлення про помилку у фреймворку має бути надзвичайно легко.
Matthew Nichols

Ну, правильним способом зробити це було б, щоб його можна було замінити простим способом ... але оскільки ми не можемо цього зробити, я радий, що ви знайшли мої думки корисними.
Метью Ніколс

Здається, долар мені не потрібен, можливо ^ і $ тоді неявні.
Андерс Лінден,

Я знаю, що OP - це лише ціле число, але це швидко вийде з-під контролю, якщо врахувати десяткові числа та i18n?
phuzi

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

Зверніть увагу на те, як отримується повідомлення про помилку, ви вказуєте поточну культуру, а локалізоване повідомлення витягується з файлу ресурсів ValidationMessages (тут - специфіка культури) .resx. Якщо вам це не потрібно, просто замініть його власним повідомленням.


Це звучить набагато складніше, ніж обране мною рішення. не кажучи вже про те, що у нас немає yield returnу vb.net, хоча є певна робота. Проте я не отримую переваг цього рішення.
GtEx

Мені дуже подобається це рішення. Одне питання: ми замінюємо існуючого постачальника новим. Що робити, якщо існуючий постачальник раніше виконував не лише цю перевірку? Чи гарантовано, що видаляючи його, ми не порушуємо жодної іншої функціональності?
Алекс

7

Ось ще одне рішення, яке змінює сторону клієнта повідомлення без зміни джерела MVC3. Повна інформація в цьому дописі в блозі:

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

Коротше, що вам потрібно зробити, це включити наступний сценарій після завантаження перевірки jQuery плюс відповідний файл локалізації .

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

Дякую Філе, (+1 за), це добре знати. Але я особисто скоріше змінив MVC3 у цій конкретній проблемі. Я сподіваюся, що вони виправлять це виправлення в наступному випуску.
GtEx

4

Ви можете встановити ResourceKey класу ClientDataTypeModelValidatorProvider на ім'я глобального ресурсу, що містить ключ FieldMustBeNumeric, щоб замінити повідомлення про помилку перевірки mvc номера на власне повідомлення. Також ключовим повідомленням про помилку перевірки дати є FieldMustBeDate.

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

1
Дивно, це насправді працює! Це ResourceClassKeyправда, ніResourceKey
Вінсент Селс

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

хороша річ полягає в тому, що він не вимагає компіляції, і ви можете легко продовжити його пізніше, хоча не надійно, але швидко.


2

Перевірте це теж:

Повний посібник із перевірки в ASP.NET MVC 3 - Частина 2

Основні частини статті слідують (скопійовані).

Існує чотири окремі частини створення повнофункціонального спеціального валідатора, який працює як на клієнті, так і на сервері. Спочатку ми підкласуємо ValidationAttributeта додаємо логіку перевірки на стороні сервера. Далі ми реалізуємо IClientValidatableнаш атрибут, щоб дозволити data-*передавати атрибути HTML5 клієнту. По-третє, ми пишемо власну функцію 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;
    }        
}

Додайте новий атрибут до властивості пароля RegisterModel та запустіть програму.

[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

Завданням адаптера є зчитування data-*атрибутів HTML5 у вашому елементі форми та перетворення цих даних у форму, яку можна зрозуміти за допомогою 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");

На цьому наш власний валідатор завершено.

Для кращого розуміння зверніться до самої статті, яка містить більше опису та більш складний приклад.

HTH.


1

Я просто зробив це, а потім використав вираз регулярного виразу:

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


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

1

Або ви можете просто зробити це.

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

Сподіваюся, це допомагає.


1

Я роблю це, ставлячи це на мій погляд

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

0

У мене ця проблема в KendoGrid, я використовую скрипт в КІНЦІ Перегляду, щоб замінити data-val-number:

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

І принаймні, в кінці View я помістив:

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

0

простим методом є використання повідомлення про зміну dataanotation на ViewModel:

[Required(ErrorMessage ="الزامی")]
[StringLength(maximumLength:50,MinimumLength =2)]
[Display(Name = "نام")]
public string FirstName { get; set; }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.