Mise en correspondance des attributs de Validation de L'entité du domaine à L'OTD

j'ai une Couche Domaine entité:

public class Product
{
    public int Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set;}
}

qui a une sorte d'attributs de validation appliqués:

public class Product
{
    public int Id { get; set; }

    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    public string Name { get; set; }

    [NotLessThan0]
    public decimal Price { get; set;}
}

Comme vous pouvez le voir, j'ai fait ces attributs complètement. Quel cadre de validation (Validator de NHibernate, DataAnnotations, ValidationApplicationBlock, Castle Validator, etc.) est utilisé ici n'est pas important.

dans ma couche client, j'ai aussi une configuration standard où je n'utilise pas les entités du domaine elles-mêmes, mais plutôt map them to ViewModels (alias DTO) which my view layer uses:

public class ProductViewModel
{
    public int Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set;}
}

disons alors que je veux que mon client / vue soit capable d'effectuer quelques validations de niveau de propriété de base.

la seule façon que je vois que je peux faire ceci est de répéter les définitions de validation dans L'objet ViewModel:

public class ProductViewModel
{
    public int Id { get; set; }

    // validation attributes copied from Domain entity
    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    public string Name { get; set; }

    // validation attributes copied from Domain entity
    [NotLessThan0]
    public decimal Price { get; set;}
}

ce n'est clairement pas satisfaisant, car j'ai maintenant répété la logique métier (validation du niveau de propriété) dans la couche ViewModel (DTO).

Donc ce qui peut être fait?

en supposant que j'utilise un outil d'automatisation comme AutoMapper pour mapper mes entités de domaine à mes Dto de ViewModel, ne serait-il pas aussi cool de transférer d'une façon ou d'une autre la logique de validation pour les propriétés mappées au ViewModel aussi?

Les questions sont:

1) Est ce une bonne idée?

2) Si oui, peut-on le faire? Si non, quelles sont les solutions de rechange, le cas échéant?

Merci d'avance pour tout commentaire!

31
demandé sur Martin Suchanek 2010-01-16 01:53:21
la source

7 ответов

si vous utilisez quelque chose supportant les annotations de données, vous devriez pouvoir utiliser une classe de métadonnées pour contenir vos attributs de validation:

public class ProductMetadata 
{
    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    public string Name { get; set; }

    [NotLessThan0]
    public decimal Price { get; set;}
}

et l'ajouter dans la MetadataTypeAttribute sur le domaine de l'entité et des DTO:

[MetadataType(typeof(ProductMetadata))]
public class Product

et

[MetadataType(typeof(ProductMetadata))]
public class ProductViewModel

cela ne marchera pas avec tous les validateurs - vous devrez peut-être étendre votre cadre de validation de votre choix pour mettre en œuvre une approche similaire.

11
répondu Sam 2010-02-11 11:31:34
la source

le but de la validation est de s'assurer que les données entrant dans votre application répondent à certains critères, en gardant cela à l'esprit, le seul endroit où il est logique de valider les contraintes de propriété, comme ceux que vous avez identifiés ici, est au point où vous acceptez les données provenant d'une source non fiable ( c.-à-d. l'utilisateur ).

vous pouvez utiliser quelque chose comme le "modèle d'argent" pour élever la validation dans votre système de type de domaine et utiliser ces types de domaine dans le modèle de vue où il a du sens. Si vous avez une validation plus complexe (c'est-à-dire que vous exprimez des règles d'affaires qui exigent plus de connaissances que celles exprimées dans une propriété unique), celles-ci appartiennent aux méthodes sur le modèle de domaine qui appliquent les changements.

en bref, mettez les attributs de validation des données sur vos modèles de vue et laissez-les hors de vos modèles de domaine.

9
répondu Neal 2010-02-15 00:21:29
la source

il s'avère que AutoMapper pourrait être en mesure de le faire pour nous automatiquement, ce qui est le meilleur scénario.

AutoMapper-utilisateurs: Transfert des attributs de validation de la viewmodel?

http://groups.google.com/group/automapper-users/browse_thread/thread/efa1d551e498311c/db4e7f6c93a77302?lnk=gst&q=validation#db4e7f6c93a77302

Je n'ai pas eu le temps d'essayer les solutions proposées, mais j'ai l'intention de le faire sous peu.

4
répondu Martin Suchanek 2010-02-20 14:06:23
la source

Pourquoi ne pas utiliser une interface pour exprimer votre intention? Par exemple:

public interface IProductValidationAttributes {
    [NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
    string Name { get; set; }

    [NotLessThan0]
    decimal Price { get; set;}
}
3
répondu JontyMC 2010-01-16 04:52:17
la source

si vous utilisez des entités de domaine écrites à la main, pourquoi ne pas mettre vos entités de domaine dans leur propre assemblage et utiliser ce même assemblage à la fois sur le client et le serveur. Vous pouvez réutiliser les mêmes validations.

1
répondu ASharp 2010-02-16 18:55:42
la source

je considère cela aussi depuis un certain temps maintenant. Je comprends totalement sa réponse. Cependant, supposons que je souhaite utiliser un autre cadre de validation qui est approprié pour annoter à la fois les entités du domaine et les modèles de vue.

La seule solution que je peux trouver sur papier qui fonctionne encore avec des attributs serait de créer un autre attribut qui "pointe" vers la propriété d'une entité de domaine que vous reproduisez dans votre modèle de vue. Voici un exemple:

// In UI as a view model.
public class UserRegistration {
  [ValidationDependency<Person>(x => x.FirstName)]
  public string FirstName { get; set; }

  [ValidationDependency<Person>(x => x.LastName)]
  public string LastName { get; set; }

  [ValidationDependency<Membership>(x => x.Username)]
  public string Username { get; set; }

  [ValidationDependency<Membership>(x => x.Password)]
  public string Password { get; set; }
}

Un framework comme xVal pourrait éventuellement être étendu pour gérer ce nouvel attribut et exécuter les attributs de validation sur la propriété de la classe de dépendance, mais avec la valeur de propriété de votre modèle de vue. Je n'en ai pas eu le temps de la chair de ce plus.

des idées?

1
répondu ventaur 2010-02-18 02:45:01
la source

tout d'Abord, il n'y a pas de notion de "norme" entité de domaine. Pour moi, standard domain entity n'a pas de setters pour commencer. Si vous adoptez cette approche, vous pouvez avoir une api plus significative, qui transmet en fait quelque chose au sujet de votre domaine. Ainsi, vous pouvez avoir un service d'application qui traite votre DTO, crée des commandes que vous pouvez exécuter directement contre vos objets de domaine, comme SetContactInfo, ChangePrice, etc. Chacun d'entre eux peut soulever ValidationException, qui à son tour vous peut collecter dans votre service et présenter à l'utilisateur. Vous pouvez toujours laisser vos attributs sur les propriétés de dto pour une validation simple au niveau des attributs/propriétés. Pour toute autre information, consultez votre domaine. Et même si c'est une application CRUD, j'éviterais d'exposer mes entités de domaine à la couche de présentation.

0
répondu epitka 2010-01-25 16:57:27
la source