Frage

Beschreibung

Meine Lösung hat diese Projekte:

  • DAL = Modified Entity Framework
  • DTO = Datenübertragung Objekte, die sind in der Lage, sich selbst zu bestätigen
  • BL = Business Layer Dienstleistungen
  • WEB = Präsentation Asp.net MVC-Anwendung

DAL, BL und WEB alle Referenz DTO was ausgezeichnet ist.
Der Prozess in der Regel führt diese Art und Weise:

  1. Ein Web-Anforderung wird an den WEB
  2. gemacht
  3. wird WEB DTOs geschrieben
    • DTOs automagically über benutzerdefinierte Action validiert erhalten
    • Validierungsfehler werden automatisch gesammelt
  4. (Validation ist OK) WEB Anrufe in BL Bereitstellung DTOs
  5. BL in DAL Anrufe von DTOs (entweder können sie durchlaufen oder sie einfach benutzen)

DTO Validierungsproblem dann ...

Meine DTOs sind in der Lage, sich selbst zu validieren basierend auf ihren eigenen Zustand (Eigenschaften Werte). Aber jetzt bin ich mit einem Problem dargestellt, wenn dies nicht der Fall ist. Ich brauche sie BL zu validieren mit (und folglich DAL).

Mein Beispiel aus der Praxis : User-Register und WEB erhält einen Benutzer DTO, die validiert wird. Der problematische Teil ist username Validierung. Seine Einzigartigkeit sollte gegen Datenspeicher überprüft werden.
Wie soll ich das tun?

Es gibt zusätzliche Informationen, dass alle DTOs eine Schnittstelle implementieren (dh. User DTO Geräte IUser) für IoC Zwecke und TDD. Beide sind Teil des DTO Projektes .

Impossible versucht

  1. Ich kann nicht BL in DTO verweisen, weil ich zirkulären Verweis bekommen.
    Compilation error
  2. Ich kann kein zusätzliches DTO.Val Projekt erstellen, die teilweise DTO Klassen verweisen würde und Umsetzung ihrer Validierung dort (sie BL + DTO verweisen würde).
    Partial classes can't span assemblies.

Mögliche versucht

  1. Erstellen Sie eine spezielle ActionFilter, das Objekt gegen äußere Bedingungen validieren würde. Dies würde man innerhalb erstellt werden WEB Projekt so sieht DTO und BL, die hier verwendet werden würde.
  2. Setzen Sie DTOs in BL und halten DTO-Schnittstellen als tatsächlicher DTOs von anderen Projekten verwiesen wird und die gesamten Code zu verwenden Schnittstellen anstelle von konkreten Klassen Refactoring.
  3. Fassen Sie externe abhängige Validierung und lassen Sie externe Abhängigkeiten werfen eine Ausnahme - wahrscheinlich das Schlimmste Lösung für dieses Problem

Was würden Sie vorschlagen?

War es hilfreich?

Lösung 4

resultierende Lösung

ich am Ende mit Controller-Aktion-Filter auf, die gegenüber äußeren Faktoren zu validieren Objekt der Lage waren, die nicht von dem Objekt erhalten werden kann selbst.

habe ich den Filter, der den Namen des Aktionsparameter nimmt zu überprüfen und Validator Typ, der diese bestimmte Parameter validiert werden. Natürlich hat diese Prüfung bestimmte Schnittstelle implementieren sie alle wiederverwendbar zu machen.

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

Validator Anforderungen diese einfache Schnittstelle implementieren

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

Es ist eine einfache und effektive Lösung für ein scheinbar komplexes Problem.

Andere Tipps

Ich würde ein Experiment vorschlagen, dass ich nur für die letzte Woche wurde erprobt oder so.

Basierend auf diese Inspiration i DTOs erschaffe, die ein wenig anders zu validieren dass der DataAnnotations Ansatz. Probe DTO:

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()
        });
    }
}

Dies könnte mehr Arbeit als DataAnnotations aussehen und gut, das ist Coz es ist, aber es ist nicht sehr groß. Ich denke, es ist mehr vorzeigbar in der Klasse (ich habe einige wirklich hässliche DTO Klassen jetzt mit DataAnnotations Attributen - Sie nicht einmal die Eigenschaften nicht mehr sehen können). Und die Macht der anonym Delegierten in dieser Anwendung ist fast buchen wert (so ist ich zu entdecken).

Basisklasse:

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 und meine Validierungsfunktionen:

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

}

Wenn mein Code sieht unordentlich gut das ist, weil ich nur schon seit den letzten Tagen auf diesem Validierungsansatz arbeiten. Ich brauche diese Idee, ein paar Anforderungen gerecht zu werden:

  • Ich brauche die IDataErrorInfo Schnittstelle zu unterstützen, damit meine MVC-Schicht automatisch validiert
  • Ich muss in der Lage sein, komplexe Validierungsszenarien zu unterstützen (der ganze Sinn Ihrer Frage ich denke): Ich möchte gegen mehrere Eigenschaften auf demselben Objekt validieren können (. Dh Startdatum und FinishDate); Eigenschaften von unterschiedlichen / multiple / verknüpften Objekten wie i in einem Objektgraph haben würde; und auch andere Dinge, die ich nicht gedacht haben noch.
  • Ich brauche die Idee eines Fehlers zu unterstützen, um mehr als eine Eigenschaft Anwendung
  • Im Rahmen meiner TDD und DDD Reise will ich meine Domain-Objekte mehr meine ‚Domain‘ zu beschreiben, als meine Dienstschicht Methoden, so diese komplexen Bedingungen in den Modellobjekten, (nicht DTOs) scheint diesen
  • zu erreichen

Dieser Ansatz ich denke, wird mir bekommen, was ich will, und vielleicht auch Sie.

Ich kann mir vorstellen, wenn Sie auf das mit mir an Bord zu springen, dass wir ziemlich ‚von uns selbst‘ sein würde, aber es könnte sich lohnen. Ich war über die

Ich hatte das exakt gleiche Problem und nach dem Versuch, für Tage und Tage und Tage eine Arbeit um zu finden, die ich am Ende meine DTO, DAL Zusammenführen und BL in einer Bibliothek. Ich hielt meine Präsentationsschicht getrennt. Nicht sicher, ob das eine Option für Sie ist oder nicht. Für mich, dachte ich, dass meine Chancen, jemals auf den Datenspeicher zu ändern waren sehr gering, und so das separate Tier nicht wirklich nötig war.

Ich habe auch die Microsoft Validation Application Block für alle meine DTO Validierungen umgesetzt. Sie haben eine „Selbstprüfung“ Methode, die Sie durchführen komplexe Validierungen können.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top