8 Stimmen

Validierung in einer mehrschichtigen Anwendung

Ich frage mich, was ist der beste Weg, um die Validierung von Datenbankbeschränkungen (z.B. UNIQUE) in einer ASP.NET MVC-Anwendung zu tun, bauen mit DDD im Verstand, wo die zugrunde liegenden Schichten sind Application Layer (Anwendungsdienste), Domain Layer (Domain-Modell) und Infrastructure Layer (Persistenz-Logik, Protokollierung, etc.).

Ich habe mir viele DDD-Beispiele angeschaut, aber viele von ihnen erwähnen nicht, wie man die Validierung im Repository durchführt (ich nehme an, dass diese Art der Validierung hierher passt). Wenn Sie von irgendwelchen Beispielen wissen, die dies tun, bitte teilen Sie sie es wird sehr geschätzt werden.

Genauer gesagt, habe ich zwei Fragen. Wie würden Sie die eigentliche Validierung durchführen? Würden Sie explizit prüfen, ob ein Kundenname bereits vorhanden ist, indem Sie die Datenbank abfragen, oder würden Sie versuchen, ihn direkt in die Datenbank einzufügen und den Fehler abzufangen, falls es einen gibt (scheint unübersichtlich)? Ich bevorzuge die erste Variante, und wenn ich mich dafür entscheide, sollte dies im Repository geschehen oder sollte es die Aufgabe eines Anwendungsdienstes sein?

Wenn der Fehler erkannt wird, wie würden Sie es an ASP.NET MVC übergeben, so dass der Benutzer freundlich über den Fehler informiert werden kann? Vorzugsweise unter Verwendung der ModelStateDictionary so dass der Fehler auf dem Formular leicht zu erkennen ist.

In der N-Lyered-App von Microsoft Spanien wird die IValidatableObject Schnittstelle und die einfachste Eigenschaftsüberprüfung wird an der Entität selbst vorgenommen, wie z. B.:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var validationResults = new List<ValidationResult>();

    if (String.IsNullOrWhiteSpace(this.FirstName))
        validationResults.Add(new ValidationResult(Messages.validation_CustomerFirstNameCannotBeNull, new string[] { "FirstName" }));

    return validationResults;
}

Bevor die Entität persistiert wird, wird die Nachricht Validate aufgerufen, um sicherzustellen, dass die Eigenschaften gültig sind:

void SaveCustomer(Customer customer)
{
    var validator = EntityValidatorFactory.CreateValidator();

    if (validator.IsValid(customer)) //if customer is valid
    {
        _customerRepository.Add(customer);
        _customerRepository.UnitOfWork.Commit();
    }
    else
        throw new ApplicationValidationErrorsException(validator.GetInvalidMessages<Customer>(customer));
}

Die ApplicationValidationErrorsException kann dann in der MVC-Anwendung abgefangen werden und die Validierungsfehlermeldungen können geparst und in die ModelStateDictionary .

Ich könnte die gesamte Validierungslogik in die SaveCustomer-Methode einbauen, z. B. die Abfrage der Datenbank, um zu prüfen, ob ein Kunde bereits in einer bestimmten Spalte (der UNIQUE-Spalte) existiert. Vielleicht ist das in Ordnung, aber ich würde es vorziehen, dass die validator.IsValid (oder etwas Ähnliches) würde dies für mich tun, oder dass die Validierung noch einmal in der Infrastrukturschicht durchgeführt wird (wenn es hierher gehört, bin ich nicht sicher).

Was meinen Sie dazu? Wie machen Sie das? Ich bin sehr daran interessiert, mehr Einblick in verschiedene Validierungstechniken bei mehrschichtigen Anwendungen zu erhalten.


Mögliche Lösung #1

Wenn die Validierungslogik nicht in der Präsentationsschicht durchgeführt werden kann (wie Iulian Margarintescu vorschlägt) und in der Serviceschicht durchgeführt werden muss, wie würden Sie Validierungsfehler an die Präsentationsschicht weitergeben?

Microsoft hat einen Vorschlag aquí (siehe Liste 5). Was halten Sie von diesem Ansatz?

0voto

Arnis Lapsa Punkte 42566

Ich frage mich, was ist der beste Weg, um die Validierung von Datenbankbeschränkungen (z. B. UNIQUE) zu tun

und wenn man sich dafür entscheidet, sollte dies im Repository geschehen oder sollte es die Aufgabe eines Anwendungsdienstes sein?

Das hängt davon ab, was Sie validieren wollen.

Wenn es sich um eine aggregierte Root-Erstellung handelt, die Sie zu validieren versuchen, dann gibt es nichts Globaleres als die App selbst, die sie "enthält". In diesem Fall wende ich die Validierung direkt im Repository an.

Wenn es sich um eine Entität handelt, lebt sie in einem aggregierten Root-Kontext. In diesem Fall überprüfe ich die Einzigartigkeit der Entität im Aggregat Root selbst anhand aller anderen Entitäten in diesem bestimmten Aggregat Root. Das Gleiche gilt für Wertobjekte in Entitäten/Wurzeln.

P.s. Repository ist eine Dienstleistung. Betrachten Sie Dienste nicht als universellen Speicher für notwendigen, aber schwer zu benennenden Code. Die Benennung ist wichtig. Das gleiche gilt für Namen wie "Helpers", "Managers", "Common", "Utilities", etc. - sie sind so gut wie bedeutungslos.

Außerdem brauchen Sie Ihre Codebasis nicht mit Musternamen zu verschmutzen: AllProducts > ProductRepository; OrderRegistrator > OrderService; order.isCompleted > IsOrderCompletedSpecification.IsSatisfiedBy.

Genauer gesagt, habe ich zwei Fragen. Wie würden Sie die eigentliche Validierung durchführen? Würden Sie explizit prüfen, ob ein Kundenname bereits existiert, indem Sie die Datenbank abfragen, oder würden Sie versuchen, ihn direkt in die Datenbank einzufügen und den Fehler abzufangen, falls es einen gibt (scheint unübersichtlich)?

Ich würde die Datenbank abfragen. Wenn es jedoch um hohe Leistung geht und die Verfügbarkeit des Kundennamens das Einzige ist, was die Datenbank erzwingen sollte, würde ich mich auf die Datenbank verlassen (1 Umweg weniger).

Wenn der Fehler erkannt wird, wie würden Sie ihn an ASP.NET MVC weitergeben, so dass der Benutzer auf angenehme Weise über den Fehler informiert werden kann? Vorzugsweise unter Verwendung des ModelStateDictionary, so dass der Fehler auf dem Formular leicht hervorgehoben wird.

Normalerweise ist es keine gute Idee, Ausnahmen für die Kontrolle des Anwendungsflusses zu verwenden, aber da ich erzwingen möchte, dass die Benutzeroberfläche nur verfügbare Dinge anzeigt, die getan werden können, werfe ich einfach eine Ausnahme, falls die Validierung fehlschlägt. In der UI-Schicht gibt es einen Handler, der das ordentlich auffängt und in HTML ausspuckt.

Außerdem ist es wichtig zu verstehen, was der Anwendungsbereich des Befehls ist (z.B. könnte ein Befehl zur Produktbestellung 2 Dinge überprüfen - ob der Kunde kein Schuldner ist und ob das Produkt im Laden ist). Wenn der Befehl mehrere zugehörige Überprüfungen hat, sollten diese miteinander gekoppelt werden, damit die Benutzeroberfläche sie gleichzeitig erhält. Andernfalls würde dies zu einer ärgerlichen Benutzererfahrung führen (mehrere Fehler beim Versuch, das verdammte Produkt immer und immer wieder zu bestellen).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X