2009-03-14 2 views
23

Когда я использую UpdateModel или TryUpdateModel, структура MVC достаточно умна, чтобы знать, пытаетесь ли вы передать нуль в тип значения (например, пользователь забывает заполнить требуемое поле «День рождения»).ASP.NET MVC - Пользовательское сообщение проверки для типов значений

К сожалению, я не знаю, как переопределить сообщение по умолчанию: «Требуется значение». в резюме во что-то более значимое («Пожалуйста, введите свой день рождения»).

Должен быть способ сделать это (без написания слишком большого кода обхода), но я не могу его найти. Любая помощь?

EDIT

Кроме того, я предполагаю, что это также будет проблемой для недействительных переходов, например, BirthDay = "Hello".

ответ

1

Ищите ModelState.AddError.

+0

Я знаю о ModelState.AddModelError(), но UpdateModel() автоматически добавляет значения в коллекцию ошибок. Разве я не понимаю ваш ответ? –

+1

Ну, когда вы проверяете, добавьте что-то в ModelState. Вот отличный учебник. http://blog.maartenballiauw.be/post/2008/08/29/Form-validation-with-ASPNET-MVC-preview-5.aspx –

+0

Я вроде как надеялся, что мне не придется все связывать, но возможно единственный способ, если мне нужны мои собственные сообщения? –

4

Я использую удивительную систему проверки подлинности xVal. Это позволяет мне выполнять всю мою проверку в модели (даже LINQ-SQL :)). Он также испускает javascript, необходимый для проверки на стороне клиента.

EDIT: К сожалению ушел из link о том, как получить это работает для LINQ-SQL

Основной рабочий процесс идет что-то вроде этого.

public partial class YourClass 
{ 
    [Required(ErrorMessage = "Property is required.")] 
    [StringLength(200)] 
    public string SomeProperty{ get; set; } 
} 

try 
{ 
    // Validate the instance of your object 
    var obj = new YourClass() { SomeProperty = "" } 
    var errors = DataAnnotationsValidationRunner.GetErrors(obj); 
    // Do some more stuff e.g. Insert into database 
} 
catch (RulesException ex) 
{ 
    // e.g. control name 'Prefix.Title' 
    ex.AddModelStateErrors(ModelState, "Prefix"); 
    ModelState.SetModelValue("Prefix.Title", new ValueProviderResult(ValueProvider["Prefix.Title"].AttemptedValue, collection["Prefix.Title"], System.Globalization.CultureInfo.CurrentCulture)); 

} 
+0

Только для записи xVal устарел [согласно] (http://xval.codeplex.com/) команде xVal. Они рекомендуют использовать его только с MVC 1.0, и он больше не поддерживается и не поддерживается. –

6

С DefaultModelBinder можно отменить сообщение об ошибке по умолчанию требуется, но, к сожалению, она будет применяться во всем мире, который IMHO делает это совершенно бесполезно. Но в случае, если вы решили сделать это вот как:

  1. Добавить папку App_GlobalResources на ваш сайт ASP.NET
  2. Добавить файл ресурсов под названием Messages.resx
  3. Внутри файла ресурсов объявить новый строковый ресурс с ключом PropertyValueRequired и некоторого значения
  4. В Application_Start добавьте следующую строку:

    DefaultModelBinder.ResourceClassKey = "Messages"; 
    

Как вы можете видеть, нет никакой связи между проверяемой моделью и сообщением об ошибке.

В заключение лучше написать специальную логику проверки для обработки этого сценария. Один из способов будут использовать обнуляемый тип (System.Nullable <TValueType>), а затем:

if (model.MyProperty == null || 
    /** Haven't tested if this condition is necessary **/ 
    !model.MyProperty.HasValue) 
{ 
    ModelState.AddModelError("MyProperty", "MyProperty is required"); 
} 
+0

Знаете ли вы, что поведение ResourceClassKey изменилось в последнее время? Это кажется сломанным в MVC 3. Док даже говорит, что он должен генерировать исключение для недопустимого класса, но он не будет, даже если я делаю DefaultModelBinder.ResourceClassKey = "lkjhjkjdswqq". –

+0

nevermind ... только что нашел ваш ответ на http://stackoverflow.com/questions/5395040/globally-localize-validation/5395297#5395297 с цитатой Брэда о том, почему это не работает :) –

3

как об этом?

[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", 
        ErrorMessage = "Characters are not allowed.")] 

Это позволит вам помечать свойства конкретных сообщений об ошибках для любой MVC валидаторов вы хотите использовать ...

2

В ASP.NET MVC 1, я тоже встретил эту проблему.

В моем проекте есть модель или бизнес-объект с именем «Entry», а его первичный ключ EntryId - int? тип, а значение EntryId может быть разрешено вводить пользователями.

Таким образом, проблема заключается в том, что, когда поле пустое или нулевое или какое-либо целочисленное значение существует, пользовательские сообщения об ошибках могут быть хорошо отображены, но если значение представляет собой некоторое нецелое значение типа «a», я могу не найти способ использовать настраиваемое сообщение для замены сообщения по умолчанию, например «Значение« a »недействительно».

, когда я отслеживать сообщение об ошибке в ModelState, я нашел, когда значение не является целым числом, то будет две ошибки, связанной с EntryID, и сообщение об ошибке первого элемента является пустым ...

Теперь у меня есть использовать такой уродливый код для взлома проблемы.

if (ModelState["EntryId"].Errors.Count > 1) 
{ 
    ModelState["EntryId"].Errors.Clear(); //should not use ModelState["EntryId"].remove(); 
    ModelState.AddModelError("EntryId", "必须为大于0的整数"); //必须为大于0的整数 means "it should be an integer value and great than 0" 
} 

, но это делает контроллер толстым, надеясь, что существует реальное решение его решения.

0

да, есть способ, вы должны использовать System.ComponentModel.DataAnnotations в сочетании с xVal и вы будете иметь возможность устанавливать правила и сообщения проверки (и может даже использовать файлы ресурсов для локализации) для каждого из вашей собственности с помощью атрибутов
посмотреть здесьhttp://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/

19

Сделать свой собственный ModelBinder путем расширения DefaultModelBinder:

public class LocalizationModelBinder : DefaultModelBinder 

Override SetProperty:

 base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value); 

     foreach (var error in bindingContext.ModelState[propertyDescriptor.Name].Errors. 
      Where(e => IsFormatException(e.Exception))) 
     { 
      if (propertyDescriptor.Attributes[typeof(TypeErrorMessageAttribute)] != null) 
      { 
       string errorMessage = 
        ((TypeErrorMessageAttribute)propertyDescriptor.Attributes[typeof(TypeErrorMessageAttribute)]).GetErrorMessage(); 
       bindingContext.ModelState[propertyDescriptor.Name].Errors.Remove(error); 
       bindingContext.ModelState[propertyDescriptor.Name].Errors.Add(errorMessage); 
       break; 
      } 
     } 

Добавьте функцию bool IsFormatException(Exception e), чтобы проверить, если исключение является FormatException:

if (e == null) 
      return false; 
     else if (e is FormatException) 
      return true; 
     else 
      return IsFormatException(e.InnerException); 

Создание класса атрибута:

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)] 
public class TypeErrorMessageAttribute : Attribute 
{ 
    public string ErrorMessage { get; set; } 
    public string ErrorMessageResourceName { get; set; } 
    public Type ErrorMessageResourceType { get; set; } 

    public TypeErrorMessageAttribute() 
    { 
    } 

    public string GetErrorMessage() 
    { 
     PropertyInfo prop = ErrorMessageResourceType.GetProperty(ErrorMessageResourceName); 
     return prop.GetValue(null, null).ToString(); 
    } 
} 

Добавить атрибут, имущество, которое вы хотите подтвердить:

[TypeErrorMessage(ErrorMessageResourceName = "IsGoodType", ErrorMessageResourceType = typeof(AddLang))] 
    public bool IsGood { get; set; } 

AddLang - это файл resx, а IsGoodType - это имя ресурса.

И, наконец, добавить это в Global.asax.cs Application_Start:

ModelBinders.Binders.DefaultBinder = new LocalizationModelBinder(); 

Ура!

+4

Отличный ответ, но есть вопрос с ним. 'propertyDescriptoy.Name' не всегда используется как ключ к' ModelState'. Вместо этого вы должны использовать унаследованный метод CreateSubPropertyName, чтобы создать ключ, например: 'ModelMetadata propertyMetadata = bindingContext.PropertyMetadata [propertyDescriptor.Name]; string propertyName = CreateSubPropertyName (bindingContext.ModelName, propertyMetadata.PropertyName); 'и затем вы можете вместо этого использовать' bindingContext.ModelState [propertyName] '. – Iravanchi

+2

Ow, ... и 'GetErrorMessage' в классе атрибута должны возвращать' ErrorMessage', если он не пуст (или наоборот). Он не учитывает случай, когда пользователь атрибута указывает сообщение об ошибке inline (без какого-либо ресурса). – Iravanchi

Смежные вопросы