Die Validierung sollte so bald wie möglich durchgeführt werden.
Die Validierung in jedem Kontext, unabhängig vom Domain-Modell oder einer anderen Art, Software zu schreiben, sollte dem Zweck dienen, WAS Sie validieren möchten und auf welcher Ebene Sie sich gerade befinden.
Aufgrund Ihrer Frage würde die Antwort wohl darin bestehen, die Validierung aufzuteilen.
Die Eigenschaftsüberprüfung prüft, ob der Wert für diese Eigenschaft korrekt ist, z. B. wenn ein Bereich zwischen 1 und 10 erwartet wird.
Die Objektvalidierung garantiert, dass alle Eigenschaften des Objekts in Verbindung miteinander gültig sind. zB BeginDate liegt vor EndDate. Angenommen, Sie lesen einen Wert aus dem Datenspeicher und sowohl BeginDate als auch EndDate werden standardmäßig mit DateTime.Min initialisiert. Beim Festlegen des BeginDate gibt es keinen Grund, die Regel "muss vor dem EndDate sein" durchzusetzen, da dies NOCH nicht zutrifft. Diese Regel sollte überprüft werden, nachdem alle Eigenschaften festgelegt wurden. Dies kann auf der aggregierten Stammebene aufgerufen werden
Die Validierung sollte auch für die aggregierte (oder aggregierte Stamm-) Entität durchgeführt werden. Ein Order-Objekt kann gültige Daten enthalten, ebenso wie seine OrderLines. In einer Geschäftsregel heißt es jedoch, dass kein Auftrag mehr als 1.000 US-Dollar betragen darf. Wie würden Sie diese Regel in einigen Fällen durchsetzen, ist dies zulässig? Sie können nicht einfach eine Eigenschaft "Betrag nicht validieren" hinzufügen, da dies zu Missbrauch führen würde (früher oder später, vielleicht sogar Sie, nur um diese "böse Anfrage" aus dem Weg zu räumen).
Als nächstes erfolgt die Validierung auf der Präsentationsebene. Wollen Sie das Objekt wirklich über das Netzwerk senden, wenn Sie wissen, dass es fehlschlagen wird? Oder ersparen Sie dem Benutzer diesen Aufwand und informieren ihn, sobald er einen ungültigen Wert eingibt. ZB ist Ihre DEV-Umgebung in den meisten Fällen langsamer als die Produktion. Möchten Sie 30 Sekunden warten, bevor Sie über "Sie haben dieses Feld WIEDER während eines weiteren Testlaufs vergessen" informiert werden, insbesondere wenn ein Produktionsfehler behoben werden muss, bei dem Ihr Chef Ihnen den Hals runter atmet?
Die Validierung auf der Persistenzebene sollte der Validierung des Eigenschaftswerts so nahe wie möglich kommen. Dies hilft dabei, Ausnahmen beim Lesen von "Null" - oder "Ungültiger Wert" -Fehlern zu vermeiden, wenn Mapper jeglicher Art oder einfache alte Datenleser verwendet werden. Die Verwendung gespeicherter Prozeduren löst dieses Problem, erfordert jedoch, dass dieselbe Bewertungslogik WIEDER geschrieben und erneut ausgeführt wird. Gespeicherte Prozeduren sind die Domäne des DB-Administrators. Versuchen Sie also nicht, auch SEINE Arbeit zu erledigen (oder stören Sie ihn noch schlimmer mit dieser "netten Auswahl, für die er nicht bezahlt wird").
Um es mit einigen berühmten Worten zu sagen: "es kommt darauf an", aber spätestens jetzt wissen Sie, WARUM es darauf ankommt.
Ich wünschte, ich könnte das alles an einem einzigen Ort unterbringen, aber das ist leider nicht möglich. Dies würde eine Abhängigkeit von einem "Gott-Objekt" erzeugen, das die ALL-Validierung für ALLE Ebenen enthält. Du willst diesen dunklen Weg nicht gehen.
Aus diesem Grund werfe ich nur Validierungsausnahmen einer Eigenschaftsstufe. Alle anderen Ebenen Ich verwende ValidationResult mit einer IsValid-Methode, um alle "defekten Regeln" zu sammeln und sie in einer einzigen AggregateException an den Benutzer zu übergeben.
Bei der Weitergabe des Aufrufstapels sammle ich diese dann erneut in AggregateExceptions, bis ich die Präsentationsebene erreiche. Die Serviceebene kann diese Ausnahme im Fall von WCF als FaultException direkt an den Client senden.
Auf diese Weise kann ich die Ausnahme annehmen und sie entweder aufteilen, um einzelne Fehler bei jedem Eingabesteuerelement anzuzeigen, oder sie reduzieren und in einer einzelnen Liste anzeigen. Es ist deine Entscheidung.
Aus diesem Grund habe ich auch die Validierung der Präsentation erwähnt, um diese so kurz wie möglich zu halten.
Falls Sie sich fragen, warum ich die Validierung auch auf der Aggregationsebene (oder auf der Serviceebene, wenn Sie möchten) habe, liegt dies daran, dass ich keine Kristallkugel habe, die mir sagt, wer meine Services in Zukunft nutzen wird. Sie werden genug Probleme haben, Ihre eigenen Fehler zu finden, um zu verhindern, dass andere Ihre Fehler machen :), indem Sie ungültige Daten eingeben. Beispielsweise verwalten Sie Anwendung A, aber Anwendung B füttert einige Daten mit Ihrem Dienst. Ratet mal, wen sie zuerst fragen, wenn es einen Bug gibt? Der Administrator von Anwendung B teilt dem Benutzer mit, dass kein Fehler aufgetreten ist. Ich gebe nur die Daten ein.