Question

Description de

Ma solution a ces projets:

  • DAL = Entity Framework
  • modifié
  • DTO = objets de transfert de données qui sont en mesure de se valider
  • BL = services de couche d'affaires
  • WEB = présentation Asp.net MVC demande

DAL, BL et WEB toute référence DTO qui est grand.
Le processus exécute habituellement de cette façon:

  1. Une demande Web est faite au WEB
  2. WEB obtient DTO affiché
    • DTO se automagiquement validés par la coutume ActionFilter
    • erreurs de validation sont collectées automatiquement
  3. (validation est OK) WEB BL remet en fournissant DTO
  4. BL remet en DAL à l'aide DTO (pouvez les passer à travers ou tout simplement les utiliser)

problème DTO validation puis ...

Mes DTO sont capables de se valider en fonction de leur propre état (valeurs propriétés). Mais en ce moment je suis présenté avec un problème lorsque ce n'est pas le cas. Je leur ai besoin de valider par BL (et par conséquent DAL).

Mon exemple réel : registres de l'utilisateur et WEB obtient un DTO utilisateur qui obtient validé. La partie problématique est la validation username. Son caractère unique doit être vérifiée par rapport à mémoire de données.
Comment suis-je censé faire?

Il y a des informations supplémentaires que tous DTO implémenter une interface (ie. User DTO implémente IUser) à des fins et TDD IoC. Les deux font partie du projet DTO .

Impossible tente

  1. Je ne peux pas faire référence à BL en DTO parce que je vais référence circulaire.
    Compilation error
  2. Je ne peux pas créer un projet DTO.Val supplémentaire qui référence les classes DTO partielles et mettre en œuvre leur validation là (ils avaient référence BL + DTO).
    Partial classes can't span assemblies.

tente possibles

  1. Créer un ActionFilter spécial qui validerait objet contre des conditions extérieures. Celui-ci serait créé dans Projet WEB voir ainsi DTO et BL qui seraient utilisés ici.
  2. Mettez DTO dans BL et maintenir des interfaces DTO comme DTO réelles référencées par d'autres projets et refactoriser tout le code à utiliser des interfaces au lieu de classes concrètes.
  3. Ne pas gérer la validation dépendante externe et laisser les dépendances externes jettent une exception - probablement le pire solution à ce problème

Que proposeriez-vous?

Était-ce utile?

La solution 4

solution résultante

I fini en utilisant un filtre d'action de contrôleur qui a pu valider l'objet contre des facteurs externes qui ne peuvent être obtenues à partir de l'objet lui-même.

J'ai créé le filtre qui prend le nom du paramètre d'action pour vérifier et le type de validateur qui validera ce paramètre particulier. Bien sûr, ce validateur doit mettre en œuvre certaines interface pour la rendre tout réutilisable.

[ValidateExternalFactors("user", typeof(UserExternalValidator))]
public ActionResult Create(User user)

validateur doit implémenter cette interface simple,

public interface IExternalValidator<T>
{
    bool IsValid(T instance);
}

Il est une solution simple et efficace à un problème apparemment complexe.

Autres conseils

Je suggère une expérience que je n'ai été Expérimentation pour la dernière semaine.

Basé sur cette inspiration je suis en train de créer DTO qui valident un peu différemment à celle de l'approche DataAnnotations. DTO de l'échantillon:

public class Contact : DomainBase, IModelObject
{
    public int ID { get; set; }
    public string Name { get; set; }
    public LazyList<ContactDetail> Details { get; set; }
    public DateTime Updated { get; set; }


    protected override void ConfigureRules()
    {
        base.AddRule(new ValidationRule()
        {
            Properties = new string[] { "name" },
            Description = "A Name is required but must not exceed 300 characters in length and some special characters are not allowed",
            validator = () => this.Name.IsRequired300LenNoSpecial()
        });

        base.AddRule(new ValidationRule()
        {
            Properties = new string[] { "updated" },
            Description = "required",
            validator = () => this.Updated.IsRequired()
        });
    }
}

Cela peut paraître plus de travail que DataAnnotations et bien, c'est coz il est, mais ce n'est pas énorme. Je pense qu'il est plus présentable dans la classe (j'ai certaines classes DTO vraiment moche maintenant avec des attributs de DataAnnotations - vous ne pouvez même pas voir les propriétés plus). Et le pouvoir des délégués anonymes dans cette application est presque digne de livre (donc je découvre).

Classe de base:

public partial class DomainBase : IDataErrorInfo
{
    private IList<ValidationRule> _rules = new List<ValidationRule>();

    public DomainBase()
    {
        // populate the _rules collection
        this.ConfigureRules();
    }

    protected virtual void ConfigureRules()
    {
        // no rules if not overridden
    }

    protected void AddRule(ValidationRule rule)
    {
        this._rules.Add(rule);
    }





    #region IDataErrorInfo Members

    public string Error
    {
        get { return String.Empty; }    // Validation should call the indexer so return "" here
    }                                   // ..we dont need to support this property.

    public string this[string columnName]
    {
        get
        {
            // get all the rules that apply to the property being validated
            var rulesThatApply = this._rules
                .Where(r => r.Properties.Contains(columnName));

            // get a list of error messages from the rules
            StringBuilder errorMessages = new StringBuilder();
            foreach (ValidationRule rule in rulesThatApply)
                if (!rule.validator.Invoke())   // if validator returns false then the rule is broken
                    if (errorMessages.ToString() == String.Empty)
                        errorMessages.Append(rule.Description);
                    else
                        errorMessages.AppendFormat("\r\n{0}", rule.Description);

            return errorMessages.ToString();
        }
    }

    #endregion
}

ValidationRule et mes fonctions de validation:

public class ValidationRule
{
    public string[] Properties { get; set; }
    public string Description { get; set; }
    public Func<bool> validator { get; set; }
}


/// <summary>
/// These extention methods return true if the validation condition is met.
/// </summary>
public static class ValidationFunctions
{
    #region IsRequired

    public static bool IsRequired(this String str)
    {
        return !str.IsNullOrTrimEmpty();
    }

    public static bool IsRequired(this int num)
    {
        return num != 0;
    }

    public static bool IsRequired(this long num)
    {
        return num != 0;
    }

    public static bool IsRequired(this double num)
    {
        return num != 0;
    }

    public static bool IsRequired(this Decimal num)
    {
        return num != 0;
    }

    public static bool IsRequired(this DateTime date)
    {
        return date != DateTime.MinValue;
    }

    #endregion


    #region String Lengths

    public static bool IsLengthLessThanOrEqual(this String str, int length)
    {
        return str.Length <= length;
    }

    public static bool IsRequiredWithLengthLessThanOrEqual(this String str, int length)
    {
        return !str.IsNullOrTrimEmpty() && (str.Length <= length);
    }

    public static bool IsRequired300LenNoSpecial(this String str)
    {
        return !str.IsNullOrTrimEmpty() &&
            str.RegexMatch(@"^[- \r\n\\\.!:*,@$%&""?\(\)\w']{1,300}$",
                RegexOptions.Multiline) == str;
    }

    #endregion

}

Si mon code semble bien compliqué qui est parce que je ne l'ai travaillé sur cette approche de validation pour les derniers jours. J'ai besoin cette idée pour répondre à quelques exigences:

  • Je dois soutenir l'interface IDataErrorInfo donc ma couche MVC valide automatiquement
  • Je dois être en mesure de soutenir des scénarios de validation complexes (le point de l'ensemble de votre question, je suppose): Je veux être en mesure de valider contre plusieurs propriétés sur le même objet (.-À-dire StartDate et finishDate); propriétés de différents objets multiples / / i associés comme auraient dans un graphe d'objet; et même d'autres choses que je n'ont pas encore pensé.
  • Je dois soutenir l'idée d'une erreur application à plus d'une propriété
  • Dans le cadre de mon TDD et voyage DDD je veux que mes objets de domaine pour décrire plus mon « domaine » que mes méthodes de couche de service, afin de mettre ces conditions complexes dans les objets du modèle (pas DTO) semble atteindre cet objectif

Cette approche je pense me faire ce que je veux, et peut-être vous aussi.

J'imagine si vous sautez à bord avec moi sur ce que nous serions assez «par nous-mêmes, mais il pourrait valoir la peine. Je lisais sur le

J'ai eu ce même problème et après avoir essayé de trouver un travail pendant des jours et des jours et des jours, j'ai fini par fusionner mon DTO, DAL et BL dans une bibliothèque. Je continuais ma couche de présentation séparée. Je ne sais pas si cela est une option pour vous ou non. Pour moi, je pensais que mes chances de changer jamais la mémoire de données étaient très légère, et donc le niveau séparé était pas vraiment nécessaire.

Je l'ai également mis en place le bloc d'application de validation de Microsoft pour tous mes DTO validations. Ils ont une méthode « auto validation » qui vous permet d'effectuer des validations complexes.

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