2013-07-31 25 views
15

Ho un modello di vista & che utilizzo sia per la modifica che per la pagina di inserimento per un record. Uno dei requisiti aziendali è che per la modifica è richiesto un determinato campo ma non un nuovo. In origine prima di questa particolare caratteristica è stato aggiunto al registro degli indagati, ho avuto il modello in questo modo:Convalida condizionale sul modello in MVC

[Required(ErrorMessage = "*")] 
[Range(0.0, (double)decimal.MaxValue)] 
[DisplayName("Cost")] 
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] 
public decimal ProposedCost { get; set; } 

Vorrei rimuovere la proprietà necessaria se si tratta di una forma di inserimento, o aggiungerlo se un modulo di modifica. Qual è l'approccio migliore? Tutta la mia altra convalida è fatta come sopra. Oppure posso modificare lo stato del modello? Pensieri?

EDIT

Qualcosa vorrei chiarire è che sono ancora permesso di inserire un costo sul nuovo, solo che non richiesto.

risposta

32

Se si utilizza MVC3/.NET4, è possibile utilizzare IValidatableObject che esiste specificamente per tali scopi.

Citando ScottGu,

... L'interfaccia IValidatableObject consente di eseguire modello a livello convalida, e consente di fornire messaggi di errore di convalida specifici per lo stato del modello complessivo ....

È modello sarà simile

public class MyViewModel : IValidatableObject 
{ 
    public long? Id { get; set; } 
    public decimal? ProposedCost { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (Id != null && ProposedCost == 0) { 
      yield return new ValidationResult("ProposedCost must be provided."); 
     } 
    } 
} 

e poi nel controller,

[HttpPost] 
public ActionResult Submit(MyViewModel model) 
{ 
    if (!ModelState.IsValid) { 
     //failed - report an error, redirect to action etc 
    } 
    //succeeded - save to database etc 
} 

In caso contrario, la soluzione più pulita sarebbe quella di utilizzare la vista modelli - UpdateViewModel dove è richiesta la proprietà, e CreateViewModel dove non è richiesto.

+0

Ho provato a farlo, tuttavia è stato comunque in grado di salvare un record di modifica senza un costo proposto. Ho inserito un punto di interruzione e ho colpito il Validationresult. Pensieri? – Seth

+0

Sei sicuro di aver controllato 'ModelState.IsValid'? Ho aggiornato la risposta per mostrare un esempio. Si noti inoltre che 'ProposedCost' deve essere annullabile se si consente di non impostarlo. – andreister

+0

Sì, mi sono perso, buona presa. Le altre proprietà aggiunte hanno un controllo lato client automaticamente dietro le quinte. Ad ogni modo posso attingere a quello? Questo ovviamente va oltre la portata della mia domanda iniziale. – Seth

3

È possibile utilizzare l'attributo di convalida RequiredIf dal progetto MVC Foolproof Validation. L'ho usato su progetti per abilitare solo la funzionalità richiesta.

Un'alternativa sarebbe utilizzare RemoteAttribute e implementare la logica da soli in un metodo.

+3

io personalmente non mi piace 'RequiredIf' perché non è il tipo di sicurezza - devi scrivere' [RequiredIf ("SomeProperty", valore, ...)] 'e significa che il compilatore non ti avviserà se 'SomeProperty' viene rinominato ma il vecchio nome è stato bloccato nell'attributo – andreister

+0

@andreister puoi usare '[RequiredIf (nameof (SomeProperty), value, ...)]' che ti dà la compilazione convalida del tempo e affronta la rinomina di 'SomeProperty' –

+0

Very true @JamesCulshaw - una delle mie caratteristiche C# preferite, perché aiuta questo scenario esatto. – christophano

0

Si può provare sulla convalida con:

ModelState.Remove("ProposedCost"); 

o estendere il vostro modello come questo:

public class NewModeViewModel : EditModeViewModel 
{ 
    public new decimal ProposedCost { get; set; } 
} 

e passando alla vista edit.

4

C'è la libreria MVC infallibile: http://foolproof.codeplex.com/

Per esempio si avrebbe bisogno di avere qualcosa di simile nel modello:

[RequiredIfTrue("Required", ErrorMessage = "*")] 
[Range(0.0, (double)decimal.MaxValue)] 
[DisplayName("Cost")] 
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] 
public decimal ProposedCost { get; set; } 

public bool Required { get; set; } 

Si sarebbe quindi necessario impostare la proprietà Required sulla base di quale forma il modello sta per.

Avrete anche bisogno di un campo di input nascosto sul modulo per rappresentare la proprietà Required se si desidera eseguire la convalida lato client.

Speranza che aiuta ...

Problemi correlati