Zum Fußzeileninhalt springen
Iron Academy Logo
Lernen Sie C#
Lernen Sie C#

Andere Kategorien

Datenvalidierung in .NET 10 Minimale APIs

Tim Corey
~10m

Minimale APIs waren immer die schlanke Alternative zu Controller-basierten ASP.NET Core, aber lange Zeit hatten sie eine bemerkenswerte Lücke: Keine eingebaute Unterstützung für die Validierung eingehender Daten. Sie mussten entweder manuelle Prüfungen in jedem Handler einbauen oder auf Drittanbieterbibliotheken zurückgreifen. .NET 10 schließt diese Lücke mit First-Class-Datenanmerkungsvalidierung für Abfragezeichenfolgen, Header und Anforderungskörper, alles ohne zusätzliche Pakete.

Dieses vertiefte Eintauchen in .NET 10 Minimal APIs, basierend auf Tim Coreys Rundgang, erklärt, wie man den Validierungsdienst registriert, Modellklassen annotiert und häufige Zugriffsmodifikator-Fallen vermeidet, die Ihr Setup stören können.

Die Einrichtung: Eine einfache minimale API

[0:44 - 1:35] Das Demo beginnt mit einem minimalen ASP.NET Core Minimal-API-Projekt, das auf .NET 10 läuft. Der Umrissbereich ist absichtlich klein: zwei POST-Endpunkte, die jeweils ein anderes Modell akzeptieren.

app.MapPost("/person", (Person person) => Results.Ok(person));
app.MapPost("/login", (LoginModel login) => Results.Ok(login));
app.MapPost("/person", (Person person) => Results.Ok(person));
app.MapPost("/login", (LoginModel login) => Results.Ok(login));

Das Person Modell enthält grundlegende Identitätsfelder. LoginModel verarbeitet Anmeldeinformationen: eine E-Mail-Adresse, ein Passwort und ein Feld zum Bestätigen des Passworts. Beide werden als JSON-Körper gesendet. Zu diesem Zeitpunkt gibt es noch keine Eingabeüberprüfung; die API akzeptiert alles, was sie erhält, einschließlich leerer Zeichenfolgen und fehlerhaft formatierter E-Mail-Adressen.

Scalar (die moderne OpenAPI-UI, die mit .NET 10 geliefert wird) wird verwendet, um Testanforderungen direkt aus dem Browser zu stellen, sodass Sie leicht sehen können, was die API vor und nach der Vernetzung der Validierung zurückgibt.

Registrierung des Validierungsdienstes

[2:36 - 3:06] Bevor irgendwelche Validierungsattribute wirksam werden, müssen Sie auf Dienstebene zustimmen. Ein einziger Aufruf in Ihrem Dienstregistrierungsblock ermöglicht die Durchsetzung über alle Minimal-API-Endpunkte:

builder.Services.AddValidation();
builder.Services.AddValidation();

Diese eine Zeile ist der gesamte Konfigurationsschritt. Es gibt keine Middleware zum Hinzufügen, keine Pipeline-Stufe zum Einhaken. Das Framework übernimmt automatisch, sobald der Dienst registriert ist. Wenn Sie diesen Aufruf überspringen, sind Ihre Datenanmerkungsattribute zwar im Modell vorhanden, werden aber nie ausgewertet, und Anforderungen weitergeleitet, unabhängig davon, was sie enthalten.

Das sollte als erster Debugging-Schritt bedacht werden: Wenn die Validierung stillschweigend nichts tut, fehlt meistens AddValidation().

Hinzufügen der Validierung zu einem Klassenmodell

[3:00 - 3:55] Mit dem registrierten Dienst ist das Hinzufügen von Validierung zu einem klassenbasierten Modell eine Frage des Dekorierens von Eigenschaften mit Datenanmerkungsattributen:

public class Person
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
}
public class Person
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
}

Nachdem die System.ComponentModel.DataAnnotations using-Direktive am Anfang der Datei hinzugefügt wurde, stellt das Markieren von FirstName und LastName als [Required] sicher, dass sie validiert werden. Das Senden einer POST-Anfrage mit leerem Body durch Scalar gibt jetzt eine 400 Bad Request mit einer strukturierten Fehlermeldung zurück:

{
  "errors": {
    "FirstName": ["The FirstName field is required."],
    "LastName": ["The LastName field is required."]
  }
}

Keine benutzerdefinierte Fehlerbehandlung, keine Filterattribute. Das Framework erstellt diese Antwort automatisch, und die Prüfung läuft vor der Ausführung Ihres Handlers, sodass Sie nie gegen null innerhalb der Endpunktlogik absichern müssen.

Validierung eines Records

[4:29 - 5:30] Die gleichen Attribute funktionieren auf C#-Records, aber die Syntax unterscheidet sich leicht, weil die Record-Eigenschaften normalerweise im primären Konstruktor und nicht als separate Mitgliedsdeklarationen definiert sind.

public record LoginModel(
    [Required] [EmailAddress] string Email,
    [Required] string Password,
    [Required] string ConfirmPassword
);
public record LoginModel(
    [Required] [EmailAddress] string Email,
    [Required] string Password,
    [Required] string ConfirmPassword
);

Attribute bei Konstruktorparametern werden auf die generierten Eigenschaften angewendet, sodass [Required] und [EmailAddress] genauso funktionieren, wie sie es in einer Klasse tun würden. Eine Anfrage mit einer fehlerhaften E-Mail, zum Beispiel "notanemail", gibt nun eine 400 zurück, die das Email Feld als ungültig identifiziert.

Das [Compare] Attribut kann auch verwendet werden, um zu erzwingen, dass ConfirmPassword mit Password übereinstimmt. Auf einem Record benötigen Attributziele einen ausdrücklichen Stupser, weil der Compiler wissen muss, dass Sie das generierte Mitglied meinen, nicht den Konstruktorparameter selbst:

[property: Compare(nameof(Password))]
string ConfirmPassword
[property: Compare(nameof(Password))]
string ConfirmPassword

Das [property:] Ziel weist den Compiler an, das Attribut an das generierte Element anstatt an den Parameter zu hängen. Ohne dies kompiliert [Compare], wird jedoch nie während der Überprüfung ausgeführt. Dies ist der kniffligste Teil des Arbeitens mit Records vs Klassen in diesem Kontext: Klasse-Eigenschaften akzeptieren Attribute natürlich, während Record-Parameter das explizite Ziel für alles benötigen, das auf Mitgliedsebene arbeitet.

Die Anforderung des öffentlichen Zugriffsschutzes

[7:51 - 9:00] Eine häufige Stolperfalle ist leicht zu übersehen und erzeugt keine Fehlermeldung, wenn Sie darauf stoßen. Das Validierungssystem verwendet Reflection, um zur Laufzeit Ihre Modelltypen zu überprüfen; damit Reflection die Mitglieder eines Typs findet, muss der Typ selbst als public markiert sein.

// Validation will NOT run; the class is internal by default
class Person { ... }

// Validation runs correctly
public class Person { ... }
// Validation will NOT run; the class is internal by default
class Person { ... }

// Validation runs correctly
public class Person { ... }

Die gleiche Regel gilt für Aufzeichnungen. Wenn Ihr Modell ohne Zugriffsmodifikator deklariert wird, setzt C# es standardmäßig auf internal, und der Dienst überspringt es vollständig. Ihr Endpunkt erhält dennoch die Anfrage, der Handler wird ausgeführt und es wird keine Fehlermeldung zurückgegeben, die Prüfungen tun einfach nichts.

Dies ist ein Verhalten von ASP.NET Core und nicht spezifisch für Minimal APIs, tritt hier jedoch häufiger auf, weil diese Projekte dazu neigen, kompakt zu sein und Entwickler manchmal Modelle inline oder in derselben Datei wie Program.cs definieren, ohne über Sichtbarkeit nachzudenken.

Ein schneller Weg, Ihr Projekt zu überprüfen: Jeder Modelltyp, der in einen Endpunkthandler übergeben wird, sollte explizit als public markiert sein. Wenn nicht, wird keine Anzahl von Attributen das Framework zwingen, zu reagieren.

Was Sie validieren können

Die eingebauten Datenanmerkungsattribute decken die häufigsten Szenarien ohne zusätzliche Arbeit ab:

  • [Required] lehnt null- oder leere Werte ab
  • [EmailAddress] validiert das Format einer E-Mail-Zeichenkette
  • [Compare] überprüft, dass zwei Eigenschaften übereinstimmen, nützlich für die Passwortbestätigung
  • [Range] erzwingt numerische oder datumsbezogene Grenzen
  • [StringLength] begrenzt die Zeichenkettenlänge mit einem optionalen Minimum
  • [RegularExpression] validiert gegen ein benutzerdefiniertes Muster

All diese funktionieren über Abfragezeichenfolgenparameter, Anfrage-Header und JSON-Körper hinweg. Die gleiche Modellklasse oder das gleiche Record kann aus verschiedenen Quellen gebunden werden, ohne dass eines seiner Attribute geändert wird.

Abschluss

[7:46 - Ende] Mit AddValidation() registriert und Ihre Modelle dekoriert, erzwingen Minimal APIs Eingabebeschränkungen automatisch über Klassen und Aufzeichnungen hinweg. Um dies in .NET 10 zum Laufen zu bringen, rufen Sie einfach einmal builder.Services.AddValidation() auf, dekorieren Sie Ihre Modelleigenschaften mit Standard-Datenanmerkungsattributen und stellen Sie sicher, dass jeder Modelltyp als public markiert ist.

Das [property:] Ziel bei Aufzeichnungen und die public Modifikatoranforderung sind die einzigen wirklichen Stolpersteine. Sie sind leicht zu übersehen und erzeugen stille Ausfälle anstelle kompiliert keine Fehler, daher halten Sie sie auf Ihrer Checkliste, wann immer Eingangsprüfungen scheinbar nichts tun.

Sehen Sie sich das vollständige Video auf Tim Coreys YouTube Kanal an, um die vollständige Quellcode-Durchsicht zu sehen.

Hero Worlddot related to Datenvalidierung in .NET 10 Minimale APIs
Hero Affiliate related to Datenvalidierung in .NET 10 Minimale APIs

Verdienen Sie mehr, indem Sie teilen, was Sie lieben

Erstellen Sie Inhalte für Entwickler, die mit .NET, C#, Java, Python oder Node.js arbeiten? Verwandeln Sie Ihr Fachwissen in ein zusätzliches Einkommen!

Iron Support Team

Wir sind 24 Stunden am Tag, 5 Tage die Woche online.
Chat
E-Mail
Rufen Sie mich an