2015-08-04 12 views
5

W moim projekcie MVC mam różne niestandardowe atrybuty walidacji. Jednym z nich jest sprawdzenie wartości nieruchomości względem wartości innej własności.C# MVC - Pobierz nazwę właściwości dynamicznie w zależności od modelu

Jak stwierdzono w wielu artykułach, dodaję coś podobnego

result.ValidationParameters.Add("otherproperty", _otherPropertyHtml); 
result.ValidationParameters.Add("comparetype", _compareType); 
result.ValidationParameters.Add("equalitytype", _equalityType); 

do powracającego ModelClientValidationRule obiektu.

Mój problem polega na tym, że jeśli moja własność do sprawdzenia jest zawarta w innym obiekcie, walidacja nie zadziała.

Jeśli tworzę coś podobnego

@Html.TextBoxFor(m => m.ValueOne) 
@Html.TextBoxFor(m => m.ValueTwo) 

walidacja będzie działać dobrze, jak to czyni

data-val-otherproperty="ValueTwo" 

Mój problem jest następujący

@Html.TextBoxFor(m => m.IntermediateObject.ValueOne) 
@Html.TextBoxFor(m => m.IntermediateObject.ValueTwo) 

ten odda dwa pola tekstowe o nazwach IntermediateObject_ValueOne i IntermediateObject.ValueTwo. Ale nadal data-val-otherproperty = "ValueOne" dla pierwszego pola tekstowego.

Jak to osiągnąć, że data-val-otherproperty ma zawsze poprawną nazwę innej właściwości?

Moje myśli są podobne do HtmlHelper <> .NameFor (m => ...) czy coś, co używa odbicia?

Update 1 - Dodano kod jako żądanie komentarzach

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, AllowMultiple = false)] 
public class CustomCompareToOther : ValidationAttribute, IClientValidatable 
{ 
    // private backing-field 
    private readonly string _otherPropertyName; 

    // constructor 
    public OemCompareToOther(string otherPropertyName) 
    { 
     _otherPropertyName = otherPropertyName; 
    } 

    // implementation of IClientValidatable 
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var result = new ModelClientValidationRule 
      { 
       ErrorMessage = FormatErrorMessage(metadata.DisplayName), 
       ValidationType = "customcomparetoother" 
      }; 

     // add the property-name so it is known when rendered for client-side validation 
     result.ValidationParameters.Add("otherproperty", _otherPropertyHtml); // here I would need IntermediateObject.ValueTwo instead of only ValueTwo 

     yield return result; 
    } 
} 

Zastosowanie w modelu poziomu byłoby

public class MyModel 
{ 
    [CustomCompareToOther("ValueOTwo", CompareType.NotEqual, PropertyType.String)] 
    public string ValueOne { get; set; }  

    [CustomCompareToOther("ValueTwo", CompareType.NotEqual, PropertyType.String)] 
    public string ValueTwo { get; set; } 
} 

A co włożę na moim zdaniem byłoby coś jak

public class ViewModel 
{ 
    public MyModel IntermediateObject { get; set; } 
} 

używane np. return View(new ViewModel()). Więc w wytopione HTML Chciałbym mieć wejście

<input type="text" name="IntermediateObject_ValueOne" id="IntermediateObject.ValueOne" data-val-customcomparetoother-otherpropertyname="ValueTwo" /> 
<input type="text" name="IntermediateObject_ValueTwo" id="IntermediateObject.ValueTwo" data-val-customcomparetoother-otherpropertyname="ValueOne" /> 

ale muszę

<input type="text" name="IntermediateObject_ValueOne" id="IntermediateObject.ValueOne" data-val-customcomparetoother-otherpropertyname="IntermediateObject.ValueTwo" /> 
<input type="text" name="IntermediateObject_ValueTwo" id="IntermediateObject.ValueTwo" data-val-customcomparetoother-otherpropertyname="IntermediateObject.ValueOne" /> 

w html tak javascript walidacja może poprawnie pobrać innej własności.

+0

dlaczego chcesz to zrobić?jeśli masz wiele modeli, które mają tak wiele podobieństwa, powinieneś udostępnić im klasę nadrzędną, wtedy możesz utworzyć widok oparty na tym rodzica – DLeh

+0

Mam zbudowaną strukturę żądania/odpowiedzi, gdzie moje 'Odpowiedź' zawiera' Żądanie' które zostaną opublikowane w następnej kolejności. Tak więc w moim 'widoku' wyrenderuję' @ Html.TextBoxFor (m => m.Request.ValueOne) '. Oczywiście, zawsze mogę dodać '" Request ".' Ale nie lubię magicznych łańcuchów, nie wszystkie części są obecnie oparte na żądaniu/odpowiedzi i jeśli nazwa zmieni się z 'Request' na' RenamedRequest', nic nie zadziała – KingKerosin

+0

Pokaż wszystkie Twój kod atrybutu: –

Odpowiedz

2

Można użyć adnotacji danych [Compare("PropertyName")].

przykład w widoku modelu:

[Display(Name = "New Password")] 
[DataType(DataType.Password)] 
public string NewPassword { get; set; } 

[Display(Name = "Confirm Password")] 
[DataType(DataType.Password)] 
[Compare("NewPassword")] 
public string PasswordConfirmation { get; set; } 

Wystarczy pamiętać, aby dodać do swoich nazw System.ComponentModel.DataAnnotations wykorzystujących sprawozdania

+0

(Dla mnie) nie ma opcji zmiany z niestandardowego atrybutu, który obecnie mam na "PorównajAttribute" – KingKerosin

Powiązane problemy