6

Utworzono niestandardowy atrybut sprawdzania poprawności CompareLessThan, kopiując atrybut porównania atrybutu ASP.NET MVC 3 i zamiast sprawdzać równość, sprawdzam, czy jedna właściwość jest mniejsza od innej. Jeśli występuje błąd po stronie klienta, komunikat "{0} musi być mniejszy niż {1}" jest wyświetlany użytkownikowi.ASP.NET MVC ValidationAttribute Pobierz inną nazwę wyświetlaną właściwości

Mój model został skonfigurowany w następujący sposób z atrybutami wyświetlania odnoszącymi się do pliku zasobów.

[CompareLessThan("AmountAvailable", ErrorMessageResourceName="CompareLessThan", ErrorMessageResourceType = typeof(Resources.ValidationMessages))] 
[Display(Name = "Amount", ResourceType = typeof(Resources.Labels))] 
public decimal Amount { get; set; } 

[Display(Name = "AmountAvailable", ResourceType = typeof(Resources.Labels))] 
public decimal AmountAvailable { get; set; } 

Następnie niestandardowy sposób GetClientValidationRules walidacji jest dokładnie taka sama jak w CompareAttribute

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
{    
    yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(OtherProperty), this.AllowEquality); 
} 

Tu generują komunikat o błędzie, który będzie wyświetlany użytkownikowi, jeśli nie jest to problem. Mogę pobrać nazwę wyświetlaną z pliku zasobów dla właściwości, która jest ozdobiona moim niestandardowym atrybutem CompareLessThan, ale moje pytanie brzmi: jak mam zamiar uzyskać nazwę wyświetlaną "innej" właściwości, z którą porównujemy? W metodzie IsValid mamy odwołanie do validationContext, z którego mogę wygenerować obiekt PropertyInfo dla właściwości "other" i myślę, że otrzymam nazwę wyświetlaną. Ale w GetClientValidationRules nie mam do tego dostępu.

Zawsze mogłem po prostu przekazać inną wartość dla wyświetlanej nazwy innej własności, ale miałem nadzieję, że istnieje sposób na jej wyprowadzenie, ponieważ już określam ją adnotacjami danych.

Wszelkie pomysły?

Odpowiedz

5

Odpowiedź udzielana przez nemesv nie działa jako własność metadata.Model ma wartość 0. Ale dzięki metadanych mamy pełną nazwę modelu, więc jest możliwe, aby utworzyć nowy wystąpienie tego modelu, a następnie utwórz nowy obiekt DataAnnonationsModelMetadataProvider z tej instancji create. Stamtąd możemy uzyskać wyświetlaną nazwę innej właściwości.

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
{ 
    Type type = Type.GetType(metadata.ContainerType.FullName); 
    var model = Activator.CreateInstance(type); 

    var provider = new DataAnnotationsModelMetadataProvider(); 
    var otherMetaData = provider.GetMetadataForProperty(() => model, type, this.OtherProperty); 

    this.otherPropertyDisplayName = otherMetaData.DisplayName; 

    yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(this.OtherProperty), this.AllowEquality); 
} 

Naprawdę nie podoba mi się to rozwiązanie (mimo że działa), ponieważ wydaje się, że powinien istnieć lepszy sposób. Czy ktoś jeszcze ma jakieś inne pomysły?

4

nie próbowałem go, ale można uzyskać właściwości modelu z własności

metadata.Properties.Single(p => p.PropertyName == "OtherPropName").DisplayName; 

EDIT metadata.Properties: Ponieważ właściwości jest pusta, co zawsze można zrobić (chociaż to bardzo elegancki). Możesz samodzielnie wygenerować metadane.

var provider = new DataAnnotationsModelMetadataProvider(); 
var otherMetaData = provider.GetMetadataForProperty(() => metaData.Model, metaData.ModelType, "OtherPropertyName"); 
+0

Dobra myśl, ale kolekcja Właściwości jest zawsze pusta. –

+0

@NickOlsen To jest smutne. Zaktualizowałem swoją odpowiedź za pomocą pewnego "obejścia". – nemesv

+0

To nie działa tak jak metadane. Właściwość Model jest tylko wartością 0. Za pomocą twojej logiki udało mi się wymyślić inny sposób, aby to zrobić (patrz inna odpowiedź), ale tak naprawdę to nie lubię. Mam nadzieję, że istnieje lepszy sposób, który może zapewnić ktoś inny. –

6

Jak z ASP.NET MVC 4 to jak udało mi się uzyskać inną właściwość:

PropertyInfo otherPropertyInfo = 
        this.Metadata.ContainerType.GetProperty(attribute.DependentProperty); 

Potem dostał Display attribute od nieruchomości:

var displayAttribute = 
    otherPropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true). 
    FirstOrDefault() as DisplayProperty; 

w Twoim przypadku:

// GetName() is important to get the translated name if you're using a resource file... 
this.otherPropertyDisplayName = displayAttribute.GetName(); 

GetName() numer referencyjny:

http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute.name%28v=vs.95%29.aspx

+0

Czy to miało być "jako DisplayProperty" lub "jako DisplayAttribute"? Mój nie działał dla DisplayProperty, ale działał dobrze dla DisplayAttribute. Świetne rozwiązanie w przeciwnym razie. – MVCKarl

+0

@MVCKarl: Myślę, że masz rację ... Może to było trochę zamieszania podczas pisania odpowiedzi tutaj. Nie mogę nagrać tego, co zrobiłem dokładnie w tym czasie. :) –

Powiązane problemy