2011-10-12 11 views
11

Qual è un buon modo per convalidare un modello quando sono richieste informazioni esterne al modello per consentire la convalida? Ad esempio, si consideri il seguente modello:ASP.NET MVC 3: convalida del modello quando sono richieste informazioni esterne al modello

public class Rating { 
    public string Comment { get; set; } 
    public int RatingLevel { get; set; } 
} 

L'amministratore di sistema può quindi impostare il RatingLevels per il quale è richiesto un commento. Queste impostazioni sono disponibili tramite un servizio di impostazioni.

Quindi, per convalidare completamente il modello ho bisogno di informazioni esterne ad esso, in questo caso il servizio di impostazioni.

Ho considerato il seguente finora:

  1. Iniettare il servizio nel modello.DefaultModelBinder utilizza System.Activator per creare l'oggetto in modo che non passi attraverso il resolver di dipendenza normale e non riesca ad iniettare il servizio nel modello senza creare un nuovo modello di raccoglitore (oltre al quale, non sembra il modo corretto andare su di esso).
  2. Inietta il servizio in un'annotazione. Non sono ancora sicuro che sia possibile, ma lo esamineremo presto. Si sente ancora goffo.
  3. Utilizzare un raccoglitore modello personalizzato. Apparentemente posso implementare OnPropertyValidating per eseguire la convalida della proprietà personalizzata. Questo sembra il più preferibile finora, anche se non sono ancora sicuro di come farlo.

Quale metodo, sopra o no, è più adatto a questo tipo di problema di convalida?

risposta

14

L'opzione 1 non si adatta. L'unico modo in cui avrebbe funzionato sarebbe quello di inserire la dipendenza tramite l'anti-pattern del locator di servizio.

L'opzione 2 non funziona . Sebbene non sia stato possibile vedere come ciò fosse possibile a causa dei requisiti degli attributi C#, è possibile.Vedere i seguenti riferimenti:

Opzione 3: Non sapevo di questo prima, ma quello che sembra essere un modo molto potente di scrivere validatori fa utilizzare la classe ModelValidator e una corrispondente ModelValidatorProvider.

In primo luogo, si crea il ModelValidatorProvider personalizzato:

public class CustomModelValidatorProvider : ModelValidatorProvider 
{ 
    public CustomModelValidatorProvider(/* Your dependencies */) {} 

    public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context) 
    { 
     if (metadata.ModelType == typeof(YourModel)) 
     { 
      yield return new YourModelValidator(...); 
     } 
    } 
} 

ASP.NET MVC di IDependencyResolver tenterà di risolvere il fornitore di sopra, così come fino a quando è registrata con il contenitore CIO non avrete bisogno di fare nulla altro. E poi il ModelValidator:

public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator 
{ 
    public EntryRatingViewModelValidatorMvcAdapter(
      ModelMetadata argMetadata, 
      ControllerContext argContext) 
       : base(argMetadata, argContext) 
    { 
     _validator = validator; 
    } 


    public override IEnumerable<ModelValidationResult> Validate(object container) 
    { 
     if (/* error condition */) 
     { 
      yield return new ModelValidationResult 
       { 
       MemberName = "Model.Member", 
       Message = "Rating is required." 
       }; 
     } 
    } 
} 

In qualità di fornitore viene recuperato attraverso la IDependencyResolver e il provider ha il pieno controllo sulle restituiti ModelValidator s sono stato facilmente in grado di iniettare le dipendenze ed eseguire la convalida necessaria.

+0

Sto usando MVC5 ma penso che quanto sopra sia ancora rilevante. Hai detto che "IDependencyResolver di MVC tenterà di risolvere il provider". Ma come registreresti il ​​provider con il contenitore IoC? (Unità nel mio caso). – Ben

1

Supponendo che si desideri convalida sia del client che del lato server del modello in base ai valori restituiti dal servizio, opterei per 2., Inietta il servizio in un'annotazione.

Fornisco un codice di esempio nella risposta a this question about adding validators to a model. L'unico passaggio aggiuntivo nel tuo caso è che dovrai inserire il tuo servizio nella tua classe ereditando dal DataAnnotationsModelValidatorProvider.

0

Che dire semplicemente semplicemente utilizzando IValidateableObject e in tale metodo determinare se la convalida è appropriata o meno e impostare gli errori lì?

How do I use IValidatableObject?

+0

Per consentire al modello di convalidarsi, è necessario accedere al servizio delle impostazioni. A meno che non utilizzi l'anti-pattern del localizzatore di servizi, dovrei creare un raccoglitore modello personalizzato per iniettare il servizio nel modello in modo che possa eseguire la convalida, nessuna delle quali sembra giusta. –

4

Si potrebbe provare fluent validation. Supporta asp.net mvc e DI in modo da poter inserire servizi esterni nei propri validatori.

+0

Sembra che abbiano fatto davvero un buon lavoro. Grazie per il link! –

Problemi correlati