2015-08-04 15 views
5

Nel mio progetto MVC ho attributi di convalida personalizzati diversi. Uno di questi è controllare il valore di una proprietà rispetto al valore di un'altra proprietà.C# MVC: richiama dinamicamente il nome della proprietà in base al modello

Come affermato in molti articoli, aggiungo qualcosa come

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

al ritorno ModelClientValidationRule oggetto.

Il mio problema ora è che, se la mia proprietà da verificare - è incapsulata in un altro oggetto, la convalida non funzionerà.

Se creo qualcosa come

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

convalida funzionerà bene come rende

data-val-otherproperty="ValueTwo" 

Il mio problema è la seguente

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

Questo renderà due caselle di testo con i nomi IntermediateObject_ValueOne e IntermediateObject.ValueTwo. Ma ancora data-val-otherproperty = "ValueOne" per la prima casella di testo.

Come si può ottenere che data-val-otherproperty abbia sempre il nome corretto dell'altra proprietà?

I miei pensieri sono qualcosa come HtmlHelper <> .NameFor (m => ...) o qualcosa che utilizza la riflessione?

Update 1 - Aggiunto codice come richiesto dai commenti

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

uso a modello a livello sarebbe

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

E quello che mi metterò nella mia View sarebbe qualcosa di simile

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

utilizzato ad es. return View(new ViewModel()). Così, nel rendering HTML vorrei avere un input

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

ma ho bisogno

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

nel codice HTML in modo javascript-convalida può recuperare correttamente l'altra proprietà.

+0

perché si vuole fare questo?se hai più modelli che hanno così tante somiglianze, dovresti farli condividere una classe genitore, quindi puoi creare una vista basata su quel genitore – DLeh

+0

Ho una struttura richiesta/risposta dove la mia 'Risposta' contiene la' Richiesta ' che verrà pubblicato successivamente. Quindi, nel mio 'View' renderò' @ Html.TextBoxFor (m => m.Request.ValueOne) '. Certo, potrei sempre aggiungere "Request". "Ma non mi piacciono le stringhe magiche, non tutte le parti sono attualmente richieste/risposte e se il nome cambia da" Request "a" RenamedRequest ", nulla funzionerà – KingKerosin

+0

Mostra tutto il codice dell'attributo –

risposta

2

È possibile utilizzare l'annotazione dei dati [Compare("PropertyName")].

esempio nella tua View Modello:

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

Basta ricordarsi di aggiungere il namespace System.ComponentModel.DataAnnotations il vostro stato usando dichiarazioni

+0

(per me) non è possibile passare dall'attributo personalizzato che attualmente ho a 'CompareAttribute' – KingKerosin

Problemi correlati