2009-03-14 11 views
23

Kiedy używam UpdateModel lub TryUpdateModel, framework MVC jest wystarczająco inteligentny, aby wiedzieć, czy próbujesz przekazać wartość zerową do typu wartości (np. Użytkownik zapomniał wypełnić wymagane pole Birth Day).ASP.NET MVC - Niestandardowy komunikat sprawdzania poprawności dla typów wartości

Niestety, nie wiem, jak zmienić domyślny komunikat "Wymagana jest wartość". w podsumowaniu w coś bardziej znaczącego ("Proszę podać w swoim Dniu Urodzenia").

Musi być sposób na zrobienie tego (bez pisania zbyt dużego kodu obejścia), ale nie mogę go znaleźć. Jakaś pomoc?

EDIT

Także myślę, że to byłoby także problemem dla nieprawidłowych konwersji, np BirthDay = "Hello".

Odpowiedz

1

Sprawdź numer ModelState.AddError.

+0

Wiem o ModelState.AddModelError(), ale UpdateModel() automatycznie dodaje wartości do kolekcji błędów. Chyba że nie rozumiem twojej odpowiedzi? –

+1

Po sprawdzeniu poprawności, dodaj coś do ModelState. Oto świetny samouczek. http://blog.maartenballiauw.be/post/2008/08/29/Form-validation-with-ASPNET-MVC-preview-5.aspx –

+0

Miałem nadzieję, że nie będę musiał sam wszystkiego wiązać, ale może jedyny sposób, jeśli chcę mieć własne wiadomości? –

4

Korzystam z niesamowitego środowiska sprawdzania poprawności . Pozwala mi wykonywać wszystkie moje walidacje w modelu (nawet LINQ-SQL :)). Emituje również javascript wymagany do sprawdzania poprawności strony klienta.

EDIT: Niestety pominął link jak uzyskać go pracy dla LINQ-SQL

Podstawowym workflow coś takiego.

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

Po prostu dla zapisu, xVal jest przestarzałe [zgodnie z] (http://xval.codeplex.com/) do zespołu xVal. Zalecają jedynie używanie go z MVC 1.0 i nie jest już aktywnie utrzymywany ani rozwijany. –

6

Z DefaultModelBinder możliwe jest, aby zastąpić domyślny wymagane komunikat o błędzie, ale niestety to zastosowanie na całym świecie, które IMHO czyni go całkowicie bezużyteczne. Jednak w przypadku, gdy zdecydujesz się to zrobić oto jak:

  1. Dodaj folder App_GlobalResources witrynie ASP.NET
  2. Dodaj plik zasobów nazwie Messages.resx
  3. Wewnątrz pliku zasobów zadeklarować nowy zasób ciąg z kluczem PropertyValueRequired i pewnej wartości
  4. W Application_Start dodać następujący wiersz:

    DefaultModelBinder.ResourceClassKey = "Messages"; 
    

Jak widać, nie ma łącza między właściwością modelu, którą sprawdzasz, a komunikatem o błędzie.

Podsumowując, lepiej jest napisać niestandardową logikę walidacji, aby obsłużyć ten scenariusz. Jednym ze sposobów byłoby użyć zerowalne typu (System.Nullable <TValueType>), a następnie:

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

Czy wiesz, czy zachowanie ResourceClassKey zmieniło się ostatnio? Wydaje się to zepsute w MVC 3. Doc mówi nawet, że powinien wyrzucić wyjątek dla niepoprawnej klasy, ale nie będzie, nawet jeśli zrobię DefaultModelBinder.ResourceClassKey = "lkjhjkjdswqq". –

+0

nevermind ... właśnie znalazłem odpowiedź na http://stackoverflow.com/questions/5395040/globally-localize-validation/5395297#5395297 z cytatem Brada o tym, dlaczego to nie działa :) –

3

jak o tym?

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

To powinno pozwalają na oznaczanie właściwości konkretnych komunikatów o błędach na cokolwiek MVC Walidatory chcesz używać ...

2

w ASP.NET MVC 1, poznałem ten problem zbyt.

W moim projekcie istnieje model lub obiekt biznesowy o nazwie "Wejście", a klucz podstawowy EntryId to int? typ, a wartość EntryId może zostać wprowadzona przez użytkowników.

Problem polega na tym, że gdy pole jest puste lub zero lub istnieje pewna liczba całkowita, które istnieją, niestandardowe komunikaty o błędach mogą być dobrze wyświetlane, ale jeśli wartość jest jakąś niecałkowitą wartością typu "a", mogę nie znaleźć sposobu na użycie niestandardowej wiadomości, aby zastąpić domyślny komunikat, taki jak "Wartość" a "jest nieprawidłowa".

kiedy śledzić komunikat o błędzie w ModelState, znalazłem, gdy wartość nie jest liczbą całkowitą, będą dwa błędy związane z EntryId, a komunikat o błędzie pierwszy element jest pusty ...

Teraz mam użyć tak paskudnego kodu, aby zhackować problem.

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

ale to sprawia, że ​​kontroler tłuszczu, mam nadzieję, że istnieje prawdziwe rozwiązanie, aby go rozwiązać.

19

Zrób swój własny ModelBinder rozszerzając DefaultModelBinder:

public class LocalizationModelBinder : DefaultModelBinder 

Zastąp 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; 
      } 
     } 

Dodaj funkcję bool IsFormatException(Exception e) aby sprawdzić, czy wyjątek jest FormatException:

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

Utwórz klasę atrybutu:

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

dodać atrybut do właściwość, którą chcesz sprawdzić:

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

AddLang to plik resx, a IsGoodType to nazwa zasobu.

I wreszcie dodać to do Global.asax.cs Application_Start:

ModelBinders.Binders.DefaultBinder = new LocalizationModelBinder(); 

Cheers!

+4

Świetna odpowiedź, ale jest problem z tym. 'propertyDescriptoy.Name' nie zawsze jest używany jako klucz do' ModelState'. Zamiast tego należy użyć dziedziczonej metody "CreateSubPropertyName", aby utworzyć klucz, na przykład: 'Właściwość ModelMetadataMetadata = bindingContext.PropertyMetadata [propertyDescriptor.Name]; string propertyName = CreateSubPropertyName (bindingContext.ModelName, propertyMetadata.PropertyName); 'a następnie możesz użyć' bindingContext.ModelState [propertyName] '. – Iravanchi

+2

Ow, ... i 'GetErrorMessage' w klasie atrybutów powinny zwracać komunikat' ErrorMessage', jeśli nie jest pusty (lub odwrotnie). Nie bierze pod uwagę, że użytkownik tego atrybutu określa komunikat o błędzie inline (bez żadnego zasobu). – Iravanchi

Powiązane problemy