Question

Quand je commencé à utiliser xVal pour la validation côté client, je ne faisais que des méthodes de mise en œuvre d'action qui a utilisé le modèle de domaine objets en tant que viewmodel ou instances intégrées de ces objets dans le viewmodel.

Cette approche fonctionne bien la plupart du temps, mais il y a des cas où la vue doit afficher et republier un sous-ensemble des propriétés du modèle (par exemple lorsque l'utilisateur souhaite mettre à jour son mot de passe, mais pas le reste de sa le profil de données).

Un (laid) solution de contournement est d'avoir un champ caché dans le formulaire pour chaque propriété qui ne sont pas autrement présents sur le formulaire.

Apparemment, la meilleure pratique consiste à créer ici une viewmodel personnalisée qui ne contient que des propriétés pertinentes à la vue et alimenter le viewmodel via Automapper . Il est beaucoup plus propre que je ne fais que transférer les données pertinentes à la vue, mais il est loin d'être parfait car je dois répéter les mêmes attributs de validation qui sont déjà présents sur l'objet modèle de domaine.

Idéalement, je voudrais préciser l'objet modèle de domaine en tant que classe méta via un attribut MetaData (ce qui est souvent appelée « classe ami »), mais cela ne fonctionne pas depuis xVal lance lorsque la classe de métadonnées a propriétés qui ne sont pas présentes sur le viewmodel.

Y at-il solution élégante à ce? J'ai envisage le piratage du code source xVal, mais peut-être il y a une autre façon que je l'ai négligé jusqu'à présent.

Merci,

Adrian

Modifier Avec l'arrivée de ASP.NET MVC 2, cela est non seulement un problème lié aux attributs de validation plus, mais elle applique également aux attributs de l'éditeur et d'affichage.

Était-ce utile?

La solution

Ceci est la raison pour laquelle la quintessence de vos écrans d'entrée ne doivent pas être étroitement à votre modèle. Cette question apparaît en fait ici sur l'étiquette MVC environ 3-4 fois par mois. Je dupe si je pouvais trouver la question précédente et une partie de la discussion de commentaire ici est intéressant. ;)

La question que vous ayez est que vous essayez de forcer deux contextes différents de validation d'un modèle dans un modèle unique qui échoue dans une grande quantité de scénarios. Le meilleur exemple est la signature d'un nouvel utilisateur, puis d'avoir un administrateur modifier un champ utilisateur plus tard. Vous devez valider un mot de passe sur un objet utilisateur lors de l'inscription, mais vous ne pourrez pas afficher le champ de mot de passe à l'administrateur de modifier les détails de l'utilisateur.

Les choix pour se déplacer ce sont tous les sous-optimale. Je travaille sur ce problème pour 3 projets maintenant et mettre en œuvre les solutions suivantes n'a jamais été propre et le plus souvent frustrant. Je vais essayer d'être pratique et d'oublier toutes les DDD / db / modèle / discussions hotnessofthemonth tout le monde est d'avoir.

1) Plusieurs modèles Voir  Ayant viewmodels qui sont presque le même constitue une violation du principe SEC, mais je sens que les coûts de cette approche sont très bas. En général, il ne respecte pas les amplis tarir les coûts d'entretien, mais à mon humble avis les coûts de ce sont les plus bas et ne pas grand'chose. Hypothétiquement vous ne changez pas comment les caractères nombre maximum le champ LastName peut avoir très souvent.

2) métadonnées dynamiques Il y a des crochets dans MVC 2 pour fournir vos propres métadonnées pour un modèle. Avec cette approche, vous pourriez avoir quel que soit votre utilisation pour fournir des métadonnées excluent certains champs en fonction du courant HTTPRequest et donc l'action et le contrôleur. Je l'ai utilisé cette technique pour construire une base de données du système d'autorisations entraîné qui va à la DB et indique la sous-classe de la DataAnnotationsMetadataProvider exclure des valeurs basées propriétés stockées dans la base de données.

Cette technique fonctionne grande atmosphère, mais le seul problème est avec UpdateModel() valider. Pour résoudre ce problème, nous avons créé une méthode SmartUpdateModel() qui va également à la base de données et génère automatiquement le tableau de chaînes ne comprennent pas [] de sorte que tous les champs non permissisable ne sont pas validées. Nous avons bien sûr mises en cache ceci pour des raisons de rendement pour son pas mal.

Je veux juste rappeler que nous avons utilisé [ValidationAttributes] sur nos modèles et les superceeded avec de nouvelles règles sur l'exécution. Le résultat final est que le champ de user.lastName [Required] n'a pas été validé si l'utilisateur n'a pas l'autorisation d'y accéder.

3) Interface fou Dynamic Thing Proxy La dernière technique que j'ai essayé de était d'utiliser des interfaces pour ViewModels. Le résultat final est que j'avais un objet utilisateur qui a hérité d'interfaces comme IAdminEdit et IUserRegistration. IAdminEdit et IUserRegistration comporterait à la fois des attributs DataAnnotation qui a effectué tout le contexte de validation spécifique comme une propriété de mot de passe avec les interfaces.

Il a fallu un peu et était plus carriole un exercice académique que toute autre chose. Le problème avec 2 et 3 est que UpdateModel et le fournisseur DataAnnotationsAttribute nécessaires pour être personnalisé pour être mis au courant de cette technique.

Mon plus grand bloc d'achoppement est que je ne veux plus jamais envoyer le tout objet utilisateur à la vue donc je fini par utiliser les procurations dynamiques pour créer des instances d'exécution de IAdminEdit

Je comprends maintenant c'est une question très spécifique xVal mais toutes les routes menant à la validation dynamique comme cela a conduit à la personnalisation des fournisseurs internes MVC métadonnées. Étant donné que tous les trucs de métadonnées est nouveau rien que propre ou simple à faire à ce stade. Le travail que vous auriez à faire pour personnaliser le comportement de validation de MVC n'est pas difficile, mais nécessite une certaine connaissance approfondie de la façon dont tous les travaux de fonctionnement interne.

Autres conseils

Nous avons déménagé notre validation attribue à la couche ViewModel. Dans notre cas, cela a fourni une séparation plus propre des préoccupations de toute façon, comme nous avons pu concevoir notre modèle de domaine tel qu'il ne pouvait pas entrer dans un état non valide en premier lieu. Par exemple, la date peut être nécessaire sur un objet BillingTransaction. Donc, nous ne voulons pas faire Nullable. Mais sur notre ViewModel, nous pourrions avoir besoin d'exposer Nullable telle que nous pouvons saisir la situation dans laquelle l'utilisateur n'a pas une valeur.

Dans d'autres cas, vous pourriez avoir la validation qui est spécifique par page / formulaire, et vous aurez envie de valider en fonction de la commande, l'utilisateur tente d'effectuer, plutôt que de mettre un tas de choses et demander au modèle de domaine, « êtes-vous valide pour essayer de faire XYZ », où à faire « ABC » ces valeurs sont valides.

Si ViewModels sont hypothétiquement forcés sur vous, alors je recommande qu'ils appliquent seulement aux exigences de domaine agnostique. Cela inclut des choses comme « nom d'utilisateur est nécessaire » et « e-mail est formaté correctement ».

Si vous dupliquez la validation des modèles de domaine dans les modèles de vue, alors vous avez couplé étroitement le domaine à l'interface utilisateur. Lorsque les changements de validation de domaine ( « ne peut appliquer 2 coupon par semaine » devient « ne peut appliquer 1 coupon par semaine »), l'interface utilisateur doit être mis à jour. D'une manière générale, ce serait terrible, et préjudiciable à l'agilité.

Si vous déplacez la validation des modèles de domaine à l'interface utilisateur, vous avez vidait votre domaine et placé la responsabilité de la validation sur l'interface utilisateur. Une deuxième interface utilisateur devrait dupliquer tout la validation, et que vous avez couplé deux séparés ensemble de l'interface utilisateur. Maintenant, si le client veut une interface spéciale pour gérer l'inventaire de leur iPhone, le projet iPhone a besoin de reproduire toute la validation qui se trouve également dans l'interface utilisateur du site. Ce serait encore plus terrible que la duplication de validation décrit ci-dessus.

Sauf si vous pouvez prédire l'avenir et peut écarter ces possibilités, seulement de valider les exigences de domaine agnostique.

Je ne sais pas comment cela va jouer pour la validation côté client, mais si la validation partielle est votre problème, vous pouvez modifier le DataAnnotationsValidationRunner discuté ici pour prendre dans une liste de IEnumerable<string> des noms de propriété, comme suit:

public static class DataAnnotationsValidationRunner
{
     public static IEnumerable<ErrorInfo> GetErrors(object instance, IEnumerable<string> fieldsToValidate)
     {
           return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>().Where(p => fieldsToValidate.Contains(p.Name))
                  from attribute in prop.Attributes.OfType<ValidationAttribute>()
                  where !attribute.IsValid(prop.GetValue(instance))
                  select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
     }
}

Je suis le risque va les downvotes et indiquer qu'il n'y a aucun avantage à ViewModels (dans ASP.NET MVC), compte tenu en particulier les frais généraux de la création et de les maintenir. Si l'idée est de découpler du domaine, qui est indéfendable. Une interface utilisateur découplé d'un domaine n'est pas une interface utilisateur pour ce domaine. L'interface utilisateur doit dépendent du domaine, de sorte que vous êtes soit allez avoir vos vues / Actions couplées au modèle de domaine, ou votre logique de gestion de ViewModel couplé au modèle de domaine. L'argument de l'architecture est donc sans objet.

Si l'idée est d'empêcher les utilisateurs de piratage POSTs HTTP malveillants qui profitent du modèle de ASP.NET MVC se liant à muter les champs ne doivent pas être autorisés à changer, puis A) le domaine doit respecter cette exigence, et B) les actions devraient fournir des propriétés whitelists actualisables au modèle de liaison.

Sauf si vous êtes domaine expose quelque chose de fou comme un live, en mémoire graphique d'objets plutôt que des copies de l'entité, sont ViewModels efforts gaspillés. Donc, pour répondre à votre question, garder la validation de domaine dans le modèle de domaine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top