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

Andere Kategorien

Einen DELETE-Endpunkt in .NET Aspire auf Linux hinzufügen

[[academy-video-youtube({"vid": "x10CYBXrLxg", "start_time": "0", "title": "Adding a DELETE Endpoint in .NET Aspire on Linux", "creator": "Tim Corey", "length": "8m 40s"})]]

Jede CRUD-API benötigt schließlich eine Möglichkeit, Datensätze zu entfernen, und das DELETE-Verb vervollständigt die vier Kerne-HTTP-Operationen neben GET, POST und PUT. Im Vergleich zu den anderen Verben ist DELETE strukturell das einfachste: kein Anfragetext, keine Validierungspipeline, kein komplexer Rückgabetyp. Was es einführt, ist eine Designfrage, auf die es keine universell richtige Antwort gibt, nämlich was zurückgegeben werden soll, wenn der Anrufer einen nicht existierenden Datensatz löschen möchte.

In seinem Video "Hinzufügen eines DELETE-Endpunkts in .NET Aspire auf Linux" schließt Tim Corey die Tiny Ticket-API ab, indem er den letzten Endpunkt hinzufügt, eine Inkonsistenz bei der Groß-/Kleinschreibung eines Parameters behebt, die im GET-by-ID gespeicherten Prozedur stillschweigend existiert hatte, und diskutiert, wann bei einem fehlenden Datensatz ein 404 im Vergleich zu einem 204 zurückgegeben werden sollte. Die Episode bietet auch einen Ausblick auf die Verlagerung auf das Frontend, das der Schwerpunkt der nächsten Phase der C# auf Linux-Serie wird. Wenn Sie die Serie verfolgt haben oder DELETE in einer Minimal-API zum ersten Mal verdrahten, führt dieser Artikel durch den vollständigen Endpunkt und das kleine Refactoring, das die Parameterbindung im gesamten Projekt konsistent machte.

Zuweisung des DELETE-Endpunkts

[1:02 - 2:14] Die Endpunktregistrierung folgt der gleichen Form wie die anderen Routen, mit zwei Anpassungen. Der Pfad enthält ein {id:int} Segment, sodass die ID in der URL und nicht im Body übermittelt wird, und die Handler-Signatur verwendet MapDelete anstelle von MapPost oder MapPut. Es gibt keinen Eingabedatensatz, da nichts anderes als der Identifikator benötigt wird.

app.MapDelete("/api/tickets/{id:int}",
    async Task<Results<NoContent, ValidationProblem>>
    (ISqlDataAccess sql, int id) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Delete",
        new { Id = id }, "TicketDB");
    return TypedResults.NoContent();
});
app.MapDelete("/api/tickets/{id:int}",
    async Task<Results<NoContent, ValidationProblem>>
    (ISqlDataAccess sql, int id) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Delete",
        new { Id = id }, "TicketDB");
    return TypedResults.NoContent();
});

Der Handler ruft das gespeicherte Verfahren spTickets_Delete über den Dapper-Wrapper auf und übergibt ein anonymes Objekt mit der ID. Die Rückgabe von TypedResults.NoContent() erzeugt einen 204-Status, was signalisiert, dass die Operation erfolgreich war und es keinen Antwortinhalt zurückzugeben gibt. Die Rückgabetyperklärung spiegelt den PUT-Endpunkt aus der vorherigen Folge wider, da beide Operationen aus Sicht des Frameworks die gleiche Palette möglicher Ergebnisse haben.

Behebung der Inkonsistenz bei der Groß-/Kleinschreibung von Parametern

[2:14 - 4:32] Während des Verdrahtens des DELETE-Aufrufs bemerkt Tim Eine Inkonsistenz, die er früher in der Serie eingeführt hatte. Das gespeicherte Verfahren spTickets_Delete verwendet einen Großbuchstaben-Id Parameter, was bedeutet, dass das anonyme Objekt eine explizite Id = id Zuweisung benötigt. Das Verfahren spTickets_Update verwendet ebenfalls Großbuchstaben-Id. Aber spTickets_Get, das Verfahren hinter dem GET-by-ID-Endpunkt, verwendet einen Kleinbuchstaben-id. Diese Kleinbuchstabenvariante ließ den ursprünglichen Handler new { id } ohne die explizite Zuweisung weitergeben, was sich seinerzeit bequem anfühlte, aber die Codebasis inkonsistent ließ.

Anstatt die Asymmetrie fortzuführen, öffnet er SQL Server Management Studio und ändert das GET-Verfahren, um Großbuchstaben-Id zu verwenden:

ALTER PROCEDURE spTickets_Get
    @Id int
AS
BEGIN
    SELECT Id, Title, Description, DateCompleted, Priority, CreatedDate
    FROM dbo.Tickets
    WHERE Id = @Id;
END

Mit dem aktualisierten Verfahren benötigt der GET-Handler in der Program.cs jetzt die gleiche explizite Zuordnung, die die DELETE- und PUT-Handler verwenden, und ändert sich von new { id } zu new { Id = id }. Die Änderung ist mechanisch, aber die Begründung ist wichtig: Konsistente Parameter-Groß-/Kleinschreibung über gespeicherte Prozeduren bedeutet, dass jeder Endpunkt Parameter auf die gleiche Weise bindet, was eine kleine, aber reale Quelle der Verwirrung beim Lesen der Datenschicht später beseitigt. Eine Konvention, die nur an einem von vier Orten gilt, ist keine Konvention.

Wann ein 204 gegenüber einem 404 bei einem fehlenden Datensatz zurückgegeben wird

[4:46 - 5:46] Nachdem der Endpunkt kompiliert wurde, pausiert Tim bei einer Designfrage, die bei jeder DELETE-Implementierung auftaucht. Wenn der Anrufer eine nicht existierende ID übergibt, was sollte die API zurückgeben? Es gibt zwei vernünftige Antworten.

Das Zurückgeben von 204 NoContent, unabhängig davon, ob eine Zeile gelöscht wurde, behandelt die Anfrage als idempotent. Aus der Perspektive des Anrufers ist die Ressource verschwunden, was das Ziel war. Das ist das, was der aktuelle Handler tut, und das ist das, mit dem das Tiny Ticket-Projekt geliefert wird. Das Zurückgeben von 404 NotFound für einen fehlenden Datensatz gibt dem Anrufer mehr Informationen, erfordert jedoch, dass die gespeicherte Prozedur darüber berichtet, ob eine Zeile tatsächlich gelöscht wurde, normalerweise indem sie eine Zeilenanzahl zurückgibt, die der Handler vor der Entscheidung, welche Antwort gesendet wird, inspizieren kann.

Für eine interne CRUD-API, bei der das Frontend bereits weiß, welche IDs existieren (weil es gerade die Liste geladen hat), ist 204 in Ordnung. Für eine öffentliche API, bei der Anrufer IDs raten könnten, verhindert 404 die stille Illusion, dass Daten entfernt wurden, wenn sie nie existierten. Tim merkt an, dass die Rückgabe von 404 Informationen darüber, welche IDs in der Datenbank existieren, lecken kann, obwohl das praktische Risiko für eine Löschoperation gering ist, da die Verwendung des Endpunkts bereits Zugriff auf das Schreiben impliziert.

Testen über Swagger

[5:46 - 7:08] Mit der laufenden Datenbank startet Tim die API und öffnet Swagger. Er beginnt mit GET alle, um den aktuellen Datenbestand zu erfassen: Datensätze 1, 2, 3 aus dem ursprünglichen Seed, sowie 107, 109 und 110, die aus früheren Einfügetests übrig geblieben sind.

Er führt DELETE an 107 aus und erhält eine 204 zurück. Das Gleiche gilt für 110. Um das Verhalten bei fehlenden Datensätzen zu überprüfen, führt er DELETE an 1011 aus, eine ID, die nie in der Datenbank war. Die Antwort ist immer noch 204, ohne Angabe, dass nichts gelöscht wurde. Das ist der in dem vorherigen Abschnitt besprochene Trade-off, der nun in der tatsächlichen API-Antwort sichtbar ist.

Ein zweiter GET bestätigt den Endzustand: Die Datensätze 1, 2, 3 und 109 bleiben. Der DELETE-Endpunkt funktioniert für gültige IDs und scheitert stillschweigend für ungültige, genau wie es die Implementierung spezifiziert.

Abschließend: CRUD abgeschlossen

[7:08 - 8:38] Das Hinzufügen von DELETE vervollständigt die vier CRUD-Verben für die Tiny Ticket-API. Das gleiche Strukturmuster zieht sich durch jeden Endpunkt: Routendefinition, Name der gespeicherten Prozedur, Dapper-Datenzugriffsaufruf, eingetippte Ergebnisdarstellung. Tim ist offen, dass eine Produktions-API wahrscheinlich mehr Endpunkte hinzufügen würde, wie z.B. ein PATCH, um ein Ticket als abgeschlossen zu markieren, ohne das gesamte Objekt über das Netz zu senden, oder ein spezieller Suchendpunkt. Das Ziel der Serie ist jedoch, jede Schicht fokussiert zu halten, so dass die nächste Schicht (das Frontend) eine saubere Oberfläche hat, gegen die sie aufgerufen werden kann.

Konsistenz ist es, was das Projekt leserlich macht. Der Dapper-Wrapper, das POST-Einfügemuster, die Validierungspipeline und die eingetippten Ergebnisse kombinieren sich so, dass jeder neue Endpunkt ungefähr den gleichen Codeumfang benötigt, unabhängig davon, welches Verb er implementiert. Diese Vorhersehbarkeit ist es, was die API zu einem angenehmen Ziel für die nachfolgende Frontend-Arbeit macht.

Abschluss

[8:38 - 8:40] Das Hinzufügen eines DELETE-Endpunkts zu einer minimalen API erfordert eine MapDelete Registrierung mit einem ID-Segment im Pfad, einen Aufruf des gespeicherten Verfahrens über den Datenzugriffs-Wrapper und eine TypedResults.NoContent() Rückgabe. Der Endpunkt vervollständigt die CRUD-Oberfläche für das Tiny Ticket-Projekt und bereitet die Verlagerung auf das Frontend in der nächsten Phase der Serie vor.

Seriennavigation: Dieser Artikel ist Teil der C# auf Linux-Serie, die die Tiny Ticket-App erstellt. Vorherige: Hinzufügen eines PUT-Update-Endpunkts. Nächste Phase: Frontend-Seiten, die die API nutzen.

Beispiel-Tipp: Wenn Sie eine informativere DELETE-Antwort möchten, ohne das gespeicherte Verfahren zu ändern, erfassen Sie die betroffene Zeilenanzahl von SaveDataAsync und geben Sie ein TypedResults.NotFound() zurück, wenn die Anzahl null ist. Dies fügt den 404-Pfad hinzu, ohne die Datenschicht neu zu gestalten.

Sehen Sie sich das vollständige Video auf seinem YouTube-Kanal an und gewinnen Sie mehr Einblicke in den Aufbau von CRUD-Endpunkten in der C# auf Linux-Serie.

Hero Worlddot related to Einen DELETE-Endpunkt in .NET Aspire auf Linux hinzufügen
Hero Affiliate related to Einen DELETE-Endpunkt in .NET Aspire auf Linux hinzufügen

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