2010-04-05 20 views
1

J'ai actuellement un formulaire que je suis en train de construire qui doit prendre en charge deux versions différentes. Chaque version peut utiliser un sous-ensemble différent de champs de formulaire. Je dois faire ceci pour soutenir deux clients différents, mais je ne veux pas avoir des actions de contrôleur entièrement différentes pour les deux. Donc, j'essaie de trouver un moyen d'utiliser un modèle fortement typé avec des attributs de validation, mais certains de ces attributs sont conditionnels.Comment puis-je prendre en charge la validation conditionnelle des propriétés du modèle?

Certaines approches auxquelles je peux penser sont similaires à l'approche partial validation de steve sanderson.

Où je voudrais effacer les erreurs de modèle dans un filtre OnActionExecuting basé sur quelle version du formulaire était active.

L'autre approche que je pensais serait de briser le modèle en morceaux en utilisant quelque chose comme

class FormModel 
{ 

public Form1 Form1Model {get; set;} 
public Form2 FormModel {get; set;} 
} 

puis trouver un moyen de valider simplement la propriété appropriée en fonction de la version. Il y aurait aussi des propriétés communes sur le modèle qui s'appliquent aux deux qui seraient toujours validées.

Est-ce que quelqu'un a une bonne suggestion à ce sujet?

Répondre

3

J'ai réussi à utiliser ModelBinders pour supprimer les erreurs dont ModelState n'a pas besoin.

Voici un exemple de classeur modèle Address. Dans l'interface utilisateur, j'ai un <SELECT> pour les États américains, mais cela est caché lorsque le pays n'est pas «États-Unis» en faveur d'une zone de texte <INPUT ID=StateOrProvince>.

Le modelbinder regarde le pays et supprime les valeurs inutiles. Pour ce qui est de faire cela avec des attributs de validation, je pense que vous vous retrouvez rapidement dans un gros pétrin à moins d'avoir des règles très simples.

Astuce: Vous pouvez avoir autant de modélistes que vous le souhaitez pour discrétiser des pièces de votre modèle global. Par exemple - J'ai 2 objets Address dans mon modèle et ils obtiennent automatiquement ce comportement.

Registre:

ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder(); 

ModelBinder:

public class AddressModelBinder : DefaultModelBinder 
{ 
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     base.OnModelUpdated(controllerContext, bindingContext); 

     // get the address to validate 
     var address = (Address)bindingContext.Model; 

     // remove statecd for non-us 
     if (address.IsUSA) 
     { 
      address.StateOrProvince = string.IsNullOrEmpty(address.StateCd) ? null : CountryCache.GetStateName(address.StateCd); 
      bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateOrProvince"); 
     } 
     else 
     { 
      address.StateCd = null; 
      bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateCd"); 
     } 


     // validate US zipcode 
     if (address.CountryCode == "US") 
     { 
      if (new Regex(@"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).Match(address.ZipOrPostal ?? "").Success == false) 
      { 
       bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".ZipOrPostal", "The value " + address.ZipOrPostal + " is not a valid zipcode"); 
      } 
     } 

     // all other modelbinding attributes such as [Required] will be processed as normal 
    } 
} 
+0

J'aime cette idée Simon. Je testerai. – Jeff

+0

@jeff Je n'ai pas aimé au début - donc je suis content que vous le fassiez déjà. fonctionne très bien pour les tâches simples que je mets à –