Freigeben über


Lernprogramm: Erstellen einer controllerbasierten Web-API mit ASP.NET Core

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.

Warnung

Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der .NET- und .NET Core-Supportrichtlinie. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.

Von Tim Deschryver und Rick Anderson

In diesem Tutorial lernen Sie die Grundlagen der Erstellung einer controllerbasierten Web-API, die eine Datenbank verwendet. Ein weiterer Ansatz zum Erstellen von APIs in ASP.NET Core besteht darin, minimale APIs zu erstellen. Hilfe bei der Auswahl zwischen minimalen APIs und controllerbasierten APIs finden Sie in der Übersicht über APIs. Ein Lernprogramm zum Erstellen einer minimalen API finden Sie im Lernprogramm: Erstellen einer minimalen API mit ASP.NET Core.

Übersicht

In diesem Tutorial wird die folgende API erstellt:

Programmierschnittstelle (API) Beschreibung Anforderungstext Antworttext
GET /api/todoitems Alle To-do-Elemente abrufen Keine Array von To-do-Elementen
GET /api/todoitems/{id} Ein Element nach ID abrufen Keine Aufgabenpunkt
POST /api/todoitems Neues Element hinzufügen Aufgabenpunkt Aufgabenpunkt
PUT /api/todoitems/{id} Vorhandenes Element aktualisieren Aufgabenpunkt Keine
DELETE /api/todoitems/{id}     Löschen eines Elements Keine Keine

Das folgende Diagramm zeigt den Entwurf der App.

Der Client wird durch ein Feld auf der linken Seite dargestellt. Er sendet eine Anfrage und empfängt eine Antwort von der Anwendung, ein Feld, das auf der rechten Seite gezeichnet wird. Innerhalb des Anwendungsfeldes stellen drei Felder den Controller, das Modell und die Datenzugriffsebene dar. Die Anfrage tritt in den Controller der Anwendung ein, und Lese-/Schreibvorgänge treten zwischen dem Controller und der Datenzugriffsebene auf. Das Modell wird serialisiert und in der Antwort an den Client zurückgegeben.

Voraussetzungen

Erstellen eines Web-API-Projekts

  • Wählen Sie im Menü "Datei" die Option "Neues Projekt"> aus.
  • Geben Sie die Web-API in das Suchfeld ein.
  • Wählen Sie die Vorlage ASP.NET Core Web API aus , und wählen Sie "Weiter" aus.
  • Benennen Sie im Dialogfeld "Neues Projekt konfigurieren" das Projekt "TodoApi ", und wählen Sie "Weiter" aus.
  • Im Dialogfeld "Zusätzliche Informationen ":
    • Vergewissern Sie sich, dass das Framework.NET 9.0 (Standard Term Support) ist.
    • Bestätigen Sie, dass das Kontrollkästchen für die OpenAPI-Unterstützung aktiviert ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen für "Controller verwenden" aktiviert ist (deaktivieren Sie die Verwendung minimaler APIs ).
    • Wählen Sie "Erstellen" aus.

Hinzufügen eines NuGet-Pakets

Ein NuGet-Paket muss hinzugefügt werden, um die in diesem Tutorial verwendete Datenbank zu unterstützen.

  • Wählen Sie im Menü "Extras " die Option "NuGet-Paket-Manager > Verwalten von NuGet-Paketen für Lösung" aus.
  • Wählen Sie die Registerkarte " Durchsuchen" aus .
  • Geben Sie Microsoft.EntityFrameworkCore.InMemory in das Suchfeld ein, und wählen Sie Microsoft.EntityFrameworkCore.InMemorydann aus.
  • Aktivieren Sie das Kontrollkästchen "Projekt " im rechten Bereich, und wählen Sie dann "Installieren" aus.

Hinweis

Anleitungen zum Hinzufügen von Paketen zu .NET-Apps finden Sie in den Artikeln unter "Installieren und Verwalten von Paketen" im Workflow "Paketverbrauch" (NuGet-Dokumentation). Bestätigen Sie die richtigen Paketversionen bei NuGet.org.

Projekt ausführen

Die Projektvorlage erstellt eine WeatherForecast API mit Unterstützung für OpenAPI.

Drücken Sie STRG+F5, um die Ausführung ohne den Debugger zu starten.

Visual Studio zeigt das folgende Dialogfeld an, wenn ein Projekt noch nicht für die Verwendung von SSL konfiguriert ist:

Dieses Projekt ist für die Verwendung von SSL konfiguriert. Um SSL-Warnungen im Browser zu vermeiden, können Sie dem selbstsignierten Zertifikat vertrauen, das IIS Express generiert hat. Möchten Sie dem IIS Express SSL-Zertifikat vertrauen?

Wählen Sie "Ja " aus, wenn Sie dem IIS Express-SSL-Zertifikat vertrauen.

Das folgende Dialogfeld wird angezeigt:

Dialogfeld

Wählen Sie "Ja " aus, wenn Sie dem Entwicklungszertifikat vertrauen möchten.

Informationen zum Vertrauen in den Firefox-Browser finden Sie unter Firefox SEC_ERROR_INADEQUATE_KEY_USAGE-Zertifikatfehler.

Visual Studio startet ein Terminalfenster und zeigt die URL der ausgeführten App an. Die API wird bei https://localhost:<port>gehostet, wobei <port> eine zufällig ausgewählte Portnummer ist, die bei der Projekterstellung festgelegt ist.

...
info: Microsoft.Hosting.Lifetime[14]
   Now listening on: https://localhost:7260
info: Microsoft.Hosting.Lifetime[14]
   Now listening on: http://localhost:7261
info: Microsoft.Hosting.Lifetime[0]
   Application started. Press Ctrl+C to shut down.
...

Strg+Klicken Sie in der Ausgabe auf die HTTPS-URL, um die Web-App in einem Browser zu testen. Es ist kein Endpunkt vorhanden, https://localhost:<port>daher gibt der Browser HTTP 404 nicht gefunden zurück.

Fügen Sie /weatherforecast an die URL an, um die WeatherForecast-API zu testen. Der Browser zeigt JSON ähnlich wie im folgenden Beispiel an:

[
    {
        "date": "2025-07-16",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2025-07-17",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2025-07-18",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2025-07-19",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2025-07-20",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Testen des Projekts

In diesem Lernprogramm werden Endpunkt-Explorer- und HTTP-Dateien verwendet, um die API zu testen.

Hinzufügen einer Modellklasse

Ein Modell ist eine Reihe von Klassen, die die von der App verwalteten Daten darstellen. Das Modell für diese App ist die Klasse TodoItem.

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt. Wählen Sie "Neuen Ordner>" aus. Geben Sie dem Ordner den Namen Models.
  • Klicken Sie mit der rechten Maustaste auf den Models Ordner, und wählen Sie "Klasse> aus. Benennen Sie die Klasse TodoItem , und wählen Sie "Hinzufügen" aus.
  • Ersetzen Sie den Vorlagencode durch Folgendes:
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Die Id-Eigenschaft fungiert als eindeutiger Schlüssel in einer relationalen Datenbank.

Modellklassen können überall im Projekt platziert werden, doch gemäß der Konvention wird der Ordner Models verwendet.

Hinzufügen eines Datenbankkontexts

Der Datenbankkontext ist die Hauptklasse, die die Entity Framework-Funktionalität für ein Datenmodell koordiniert. Diese Klasse wird durch Ableiten von der Microsoft.EntityFrameworkCore.DbContext-Klasse erstellt.

  • Klicken Sie mit der rechten Maustaste auf den Models Ordner, und wählen Sie "Klasse> aus. Benennen Sie die Klasse TodoContext , und klicken Sie auf "Hinzufügen".

  • Geben Sie den folgenden Code ein:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models;
    
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }
    
        public DbSet<TodoItem> TodoItems { get; set; } = null!;
    }
    

Registrieren des Datenbankkontexts

In ASP.NET Core müssen Dienste wie der Datenbankkontext im Container der Dependency Injection (DI) registriert werden. Der Container stellt den Dienst für Controller bereit.

Aktualisieren Sie Program.cs mit dem folgenden hervorgehobenen Code:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorangehende Code:

  • Fügt using-Richtlinien hinzu.
  • Fügt dem DI-Container den Datenbankkontext hinzu.
  • Gibt an, dass der Datenbankkontext eine In-Memory Database verwendet

Erstellen eines Controllergerüsts

  • Klicken Sie mit der rechten Maustaste auf den Ordner Controllers.

  • Wählen Sie "Hinzufügen">New Scaffolded Item aus.

  • Wählen Sie API Controller mit Aktionen, mithilfe von Entity Framework, und wählen Sie dann "Hinzufügen" aus.

  • Im Dialogfenster "API-Controller mit Aktionen hinzufügen, unter Verwendung des Entitätsframeworks" :

    • Wählen Sie TodoItem (TodoApi.Models) in der Model-Klasse aus.
    • Wählen Sie TodoContext (TodoApi.Models) in der Data-Kontextklasse aus.
    • Wählen Sie "Hinzufügen" aus.

    Wenn der Gerüstvorgang fehlschlägt, wählen Sie "Hinzufügen" aus, um das Gerüst ein zweites Mal zu versuchen.

In diesem Schritt werden dem Projekt die Microsoft.VisualStudio.Web.CodeGeneration.Design und Microsoft.EntityFrameworkCore.Tools NuGet-Pakete hinzugefügt. Diese Pakete sind für das Gerüst erforderlich.

Der generierte Code:

  • Markiert die Klasse mit dem [ApiController]-Attribut. Dieses Attribut gibt an, dass der Controller auf Web-API-Anforderungen reagiert. Informationen zu bestimmten Verhaltensweisen, die das Attribut ermöglicht, finden Sie unter Erstellen von Web-APIs mit ASP.NET Core.
  • Verwendet DI, um den Datenbankkontext (TodoContext) in den Controller zu injizieren. Der Datenbankkontext wird in den einzelnen CRUD-Methoden des Controllers verwendet.

Die ASP.NET Core-Vorlagen für:

  • Controller mit Ansichten enthalten [action] in der Routenvorlage.
  • API-Controller enthalten keine [action] in der Routenvorlage.

Wenn das [action] Token nicht in der Routenvorlage enthalten ist, ist der Aktionsname (Methodenname) nicht im Endpunkt enthalten. Dies bedeutet, dass der zugehörige Methodenname der Aktion nicht in der übereinstimmenden Route verwendet wird.

Aktualisieren der PostTodoItem-Erstellungsmethode

Aktualisieren Sie die Rückgabeanweisung in PostTodoItem, um den nameof-Operator zu verwenden.

[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

Der oben stehende Code ist eine HTTP POST-Methode, wie durch das [HttpPost]-Attribut angegeben. Die Methode ruft den Wert von TodoItem aus dem Text der HTTP-Anforderung ab.

Weitere Informationen finden Sie unter Attributrouting mit Http[Verb]-Attributen.

Die CreatedAtAction-Methode:

  • Gibt bei erfolgreicher Ausführung einen HTTP 201-Statuscode zurück. HTTP 201 ist die Standardantwort für eine HTTP POST-Methode, die eine neue Ressource auf dem Server erstellt.
  • Fügt der Antwort einen Location-Header hinzu. Die Location Kopfzeile gibt den URI des neu erstellten to-do Elements an. Weitere Informationen finden Sie unter 10.2.2 2 201 Created.
  • Verweist auf die GetTodoItem-Aktion zum Erstellen des URIs des Location-Headers. Das nameof-Schlüsselwort von C# wird verwendet, um eine Hartcodierung des Aktionsnamens im CreatedAtAction-Aufruf zu vermeiden.

Testen von PostTodoItem

  • Wählen Sie ">Windows-Endpunkte-Explorer> anzeigen" aus.

  • Klicken Sie mit der rechten Maustaste auf den POST-Endpunkt , und wählen Sie "Anforderung generieren" aus.

    Kontextmenü des Endpunkte-Explorers, in dem das Menüelement

    Im Projektordner mit dem Namen TodoApi.httpwird eine neue Datei erstellt, deren Inhalt dem folgenden Beispiel ähnelt:

    @TodoApi_HostAddress = https://localhost:49738
    
    POST {{TodoApi_HostAddress}}/api/todoitems
    Content-Type: application/json
    
    {
      //TodoItem
    }
    
    ###
    
    • Die erste Zeile erstellt eine Variable, die für alle Endpunkte verwendet wird.
    • Die nächste Zeile definiert eine POST-Anforderung.
    • Die Zeilen nach der POST-Anforderungszeile definieren die Kopfzeilen und einen Platzhalter für den Anforderungstext.
    • Die Zeile mit dem dreifachen Hashtag (###) ist ein Anforderungstrennzeichen: Was danach kommt, gilt für eine andere Anforderung.
  • Die POST-Anforderung erwartet eine TodoItem. Um den Todo zu definieren, ersetzen Sie den //TodoItem Kommentar durch den folgenden JSON-Code:

    {
      "name": "walk dog",
      "isComplete": true
    }
    

    Die Datei TodoApi.http sollte nun wie im folgenden Beispiel aussehen, aber mit Ihrer Portnummer:

    @TodoApi_HostAddress = https://localhost:7260
    
    Post {{TodoApi_HostAddress}}/api/todoitems
    Content-Type: application/json
    
    {
      "name": "walk dog",
      "isComplete": true
    }
    
    ###
    
  • Führen Sie die App aus.

  • Wählen Sie den Link " Anfrage senden " aus, der sich über der Anforderungszeile POST befindet.

    .http-Dateifenster mit hervorgehobenem Ausführungslink.

    Die POST-Anforderung wird an die App gesendet, und die Antwort wird im Antwortbereich angezeigt.

    HTTP-Dateifenster mit Antwort von der POST-Anforderung.

Testen des Adressheader-URIs

Testen Sie die App, indem Sie die GET Endpunkte aus einem Browser oder mithilfe des Endpunkt-Explorers aufrufen. Die folgenden Schritte gelten für Endpunkt-Explorer.

  • Klicken Sie im Endpunkt-Explorer mit der rechten Maustaste auf den ersten GET-Endpunkt , und wählen Sie "Anforderung generieren" aus.

    Der folgende Inhalt wird der datei TodoApi.http hinzugefügt:

    GET {{TodoApi_HostAddress}}/api/todoitems
    
    ###
    
  • Wählen Sie den Link " Anforderung senden " aus, der sich oberhalb der neuen GET Anforderungszeile befindet.

    Die GET-Anforderung wird an die App gesendet und die Antwort wird im Antwortbereich angezeigt.

  • Der Antwortkörper ähnelt dem folgenden JSON.

    [
      {
        "id": 1,
        "name": "walk dog",
        "isComplete": true
      }
    ]
    
  • Klicken Sie im Endpunkt-Explorer mit der rechten Maustaste auf den /api/todoitems/{id}GET-Endpunkt , und wählen Sie "Anforderung generieren" aus. Der folgende Inhalt wird der datei TodoApi.http hinzugefügt:

    @id=0
    GET {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    
    ###
    
  • Weisen Sie {@id} zu 1 (anstelle von 0) zu.

  • Wählen Sie den Link " Anforderung senden" aus, der sich oberhalb der neuen GET-Anforderungszeile befindet.

    Die GET-Anforderung wird an die App gesendet und die Antwort wird im Antwortbereich angezeigt.

  • Der Antwortkörper ähnelt dem folgenden JSON.

    {
      "id": 1,
      "name": "walk dog",
      "isComplete": true
    }
    

Überblick über die GET-Methoden

Zwei GET-Endpunkte werden implementiert:

  • GET /api/todoitems
  • GET /api/todoitems/{id}

Der vorherige Abschnitt veranschaulichte ein Beispiel für die /api/todoitems/{id}-Route.

Folgen Sie den POST-Anweisungen , um ein weiteres Todo-Element hinzuzufügen, und testen Sie dann die /api/todoitems Route mit Swagger.

Diese App verwendet eine In-Memory-Datenbank. Wenn die App angehalten und dann wieder gestartet wird, werden durch die vorherige GET-Anforderung keine Daten zurückgegeben. Wenn keine Daten zurückgegeben werden, senden Sie POST-Daten an die App.

Routing und URL-Pfade

Das [HttpGet]-Attribut gibt eine Methode an, die auf eine HTTP GET-Anforderung antwortet. Der URL-Pfad für jede Methode wird wie folgt erstellt:

  • Beginnen Sie mit der Vorlagenzeichenfolge im Route-Attribut des Controllers:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Ersetzen Sie [controller] durch den Namen des Controllers, bei dem es sich standardmäßig um den Namen der Controller-Klasse ohne das Suffix „Controller“ handelt. Für dieses Beispiel ist der Controllerklassenname TodoItemsController, sodass der Controllername "TodoItems" lautet. ASP.NET Core Routing ist nicht groß-/kleinschreibungssensitiv.

  • Wenn das [HttpGet]-Attribut eine Routenvorlage (z. B. [HttpGet("products")]) hat, fügen Sie diese an den Pfad an. In diesem Beispiel wird keine Vorlage verwendet. Weitere Informationen finden Sie unter Attributrouting mit Http[Verb]-Attributen.

In der folgenden GetTodoItem-Methode ist "{id}" eine Platzhaltervariable für den eindeutigen Bezeichner des To-do-Elements. Wenn GetTodoItem aufgerufen wird, wird der Methode in ihrem Parameter "{id}" der Wert von id aus der URL bereitgestellt.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Rückgabewerte

Der Rückgabetyp der GetTodoItems- und GetTodoItem-Methoden ist vom ActionResult<T>-Typ. ASP.NET Core serialisiert das Objekt automatisch in JSON und schreibt den JSON-Code in den Textkörper der Antwortnachricht. Der Antwortcode für diesen Rückgabetyp ist 200 OK, vorausgesetzt, es gibt keine unbehandelten Ausnahmen. Nicht behandelte Ausnahmen werden in 5xx-Fehler übersetzt.

ActionResult-Rückgabetypen können eine Vielzahl von HTTP-Statuscodes darstellen. Beispielsweise kann GetTodoItem zwei verschiedene Statuswerte zurückgeben:

  • Wenn kein Element mit der angeforderten ID übereinstimmt, gibt die Methode den Fehlercode 404 zurückNotFound .
  • Andernfalls gibt die Methode 200 mit einem JSON-Antworttext zurück. Die Rückgabe von item löst eine HTTP 200-Antwort aus.

PutTodoItem-Methode

Untersuchen Sie die PutTodoItem-Methode.

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem ähnelt PostTodoItem, verwendet allerdings HTTP PUT. Die Antwort lautet 204 (Kein Inhalt). Gemäß der HTTP-Spezifikation erfordert eine PUT-Anforderung, dass der Client die gesamte aktualisierte Entität (nicht nur die Änderungen) sendet. Verwenden Sie HTTP PATCH, um Teilupdates zu unterstützen.

Testen der PutTodoItem-Methode

In diesem Beispiel wird eine In-Memory-Datenbank verwendet, die jedes Mal initialisiert werden muss, wenn die App gestartet wird. Es muss ein Element in der Datenbank vorhanden sein, bevor Sie einen PUT-Aufruf durchführen. Rufen Sie vor einem PUT-Aufruf GET auf, um sicherzustellen, dass ein Element in der Datenbank vorhanden ist.

Verwenden Sie die PUT-Methode, um die TodoItem mit id = 1 zu aktualisieren und den Namen auf "feed fish"festzulegen. Beachten Sie, dass die Antwort HTTP 204 No Content lautet.

  • Klicken Sie im Endpunkt-Explorer mit der rechten Maustaste auf den PUT-Endpunkt , und wählen Sie "Anforderung generieren" aus.

    Der folgende Inhalt wird der datei TodoApi.http hinzugefügt:

    PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    Content-Type: application/json
    
    {
      //TodoItem
    }
    
    ###
    
  • Ersetzen Sie in der PUT-Anforderungszeile {{id}} durch 1.

  • Ersetzen Sie den Platzhalter //TodoItem durch die folgenden Zeilen:

    PUT {{TodoApi_HostAddress}}/api/todoitems/1
    Content-Type: application/json
    
    {
      "id": 1,
      "name": "feed fish",
      "isComplete": false
    }
    
  • Wählen Sie den Link " Anforderung senden " aus, der sich oberhalb der neuen PUT-Anforderungszeile befindet.

    Die PUT-Anforderung wird an die App gesendet, und die Antwort wird im Antwortbereich angezeigt. Der Antworttext ist leer, und der Statuscode ist 204.

Die DeleteTodoItem-Methode

Untersuchen Sie die DeleteTodoItem-Methode.

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

Testen der DeleteTodoItem-Methode

Verwenden Sie die DELETE-Methode, um die TodoItem mit der ID = 1 zu löschen. Beachten Sie, dass die Antwort HTTP 204 No Content lautet.

  • Klicken Sie im Endpunkt-Explorer mit der rechten Maustaste auf den DELETE-Endpunkt , und wählen Sie "Anforderung generieren" aus.

    Eine DELETE-Anforderung wird zu TodoApi.httphinzugefügt.

  • Ersetzen Sie {{id}} in der DELETE-Anforderungszeile durch 1. Die DELETE-Anforderung sollte wie im folgenden Beispiel aussehen:

    DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    
    ###
    
  • Wählen Sie den Link " Anforderung senden " für die DELETE-Anforderung aus.

    Die DELETE-Anforderung wird an die App gesendet, und die Antwort wird im Antwortbereich angezeigt. Der Antworttext ist leer, und der Statuscode ist 204.

Testen mit anderen Tools

Es gibt viele andere Tools, die zum Testen von Web-APIs verwendet werden können, z. B.:

Vermeiden von Overposting

Derzeit macht die Beispiel-App das gesamte TodoItem-Objekt verfügbar. In den Produktions-Apps sind die Daten, die eingegeben und mithilfe einer Teilmenge des Modells zurückgegeben werden, in der Regel eingeschränkt. Hierfür gibt es mehrere Gründe, wobei die Sicherheit einer der Hauptgründe ist. Die Teilmenge eines Modells wird üblicherweise als Datenübertragungsobjekt (DTO, Data Transfer Object), Eingabemodell oder Anzeigemodell bezeichnet. DTO wird in diesem Lernprogramm verwendet.

Ein DTO kann für Folgendes verwendet werden:

  • Vermeiden Sie Overposting.
  • Eigenschaften ausblenden, die Kunden nicht sehen sollen.
  • Auslassen einiger Eigenschaften, um die Nutzlast zu verringern
  • Vereinfachen von Objektgraphen, die geschachtelte Objekte enthalten Vereinfachte Objektgraphen können für Clients zweckmäßiger sein.

Um den DTO-Ansatz zu veranschaulichen, aktualisieren Sie die TodoItem-Klasse, sodass sie ein geheimes Feld einschließt:

namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
    public string? Secret { get; set; }
}

Das geheime Feld muss in dieser App ausgeblendet werden, eine administrative App kann es jedoch verfügbar machen.

Vergewissern Sie sich, dass Sie das geheime Feld veröffentlichen und abrufen können.

Erstellen Eines DTO-Modells in einer Models/TodoItemsDTO.cs-Datei :

namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Aktualisieren Sie TodoItemsController, sodass TodoItemDTO verwendet wird:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/TodoItems
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    // GET: api/TodoItems/5
    // <snippet_GetByID>
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }
    // </snippet_GetByID>

    // PUT: api/TodoItems/5
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Update>
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
    {
        if (id != todoDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoDTO.Name;
        todoItem.IsComplete = todoDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }
    // </snippet_Update>

    // POST: api/TodoItems
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Create>
    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoDTO.IsComplete,
            Name = todoDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }
    // </snippet_Create>

    // DELETE: api/TodoItems/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id)
    {
        return _context.TodoItems.Any(e => e.Id == id);
    }

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
       new TodoItemDTO
       {
           Id = todoItem.Id,
           Name = todoItem.Name,
           IsComplete = todoItem.IsComplete
       };
}

Vergewissern Sie sich, dass Sie das geheime Feld weder veröffentlichen noch abrufen können.

Aufrufen der Web-API mit JavaScript

Siehe Lernprogramm: Aufrufen einer ASP.NET Core-Web-API mit JavaScript.

Videoreihe zur Web-API

Siehe Video: Anfängerserie zu: Web-APIs.

Enterprise Web App-Muster

Anleitungen zum Erstellen einer zuverlässigen, sicheren, leistungsfähigen, testbaren und skalierbaren ASP.NET Core-App finden Sie unter Enterprise Web App-Muster. Eine vollständige Beispielweb-App zur Produktionsqualität, die die Muster implementiert, ist verfügbar.

Hinzufügen der Authentifizierungsunterstützung zu einer Web-API

ASP.NET Core Identity fügt Benutzeroberflächen-Anmeldefunktionen zu ASP.NET Core-Web-Apps hinzu. Verwenden Sie zum Sichern von Web-APIs und SPAs eine der folgenden Optionen:

Duende Identity Server ist ein OpenID Connect- und OAuth 2.0-Framework für ASP.NET Core. Duende Identity Server ermöglicht die folgenden Sicherheitsfeatures:

  • Authentifizierung als Dienst
  • Einmaliges Anmelden und einmaliges Abmelden für mehrere Anwendungstypen
  • Zugriffssteuerung für APIs
  • Föderationsgateway

Wichtig

Duende Software erfordert möglicherweise, dass Sie eine Lizenzgebühr für die Produktionsnutzung von Duende Identity Server bezahlen. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core in .NET 5 zu .NET 6.

Weitere Informationen finden Sie in der Duende Server-Dokumentation (Duende Identity Software-Website).

Veröffentlichen in Azure

Informationen zum Bereitstellen in Azure finden Sie in der Schnellstartanleitung: Bereitstellen einer ASP.NET Web-App.

Zusätzliche Ressourcen

Beispielcode für dieses Lernprogramm anzeigen oder herunterladen. Hier erfahren Sie, wie Sie herunterladen.

Weitere Informationen finden Sie in den folgenden Ressourcen:

In diesem Tutorial lernen Sie die Grundlagen der Erstellung einer controllerbasierten Web-API, die eine Datenbank verwendet. Ein weiterer Ansatz zum Erstellen von APIs in ASP.NET Core besteht darin, minimale APIs zu erstellen. Hilfe bei der Auswahl zwischen minimalen APIs und controllerbasierten APIs finden Sie in der Übersicht über APIs. Ein Lernprogramm zum Erstellen einer minimalen API finden Sie im Lernprogramm: Erstellen einer minimalen API mit ASP.NET Core.

Übersicht

In diesem Tutorial wird die folgende API erstellt:

Programmierschnittstelle (API) Beschreibung Anforderungstext Antworttext
GET /api/todoitems Alle To-do-Elemente abrufen Keine Array von To-do-Elementen
GET /api/todoitems/{id} Ein Element nach ID abrufen Keine Aufgabenpunkt
POST /api/todoitems Neues Element hinzufügen Aufgabenpunkt Aufgabenpunkt
PUT /api/todoitems/{id} Vorhandenes Element aktualisieren Aufgabenpunkt Keine
DELETE /api/todoitems/{id}     Löschen eines Elements Keine Keine

Das folgende Diagramm zeigt den Entwurf der App.

Der Client wird durch ein Feld auf der linken Seite dargestellt. Er sendet eine Anfrage und empfängt eine Antwort von der Anwendung, ein Feld, das auf der rechten Seite gezeichnet wird. Innerhalb des Anwendungsfeldes stellen drei Felder den Controller, das Modell und die Datenzugriffsebene dar. Die Anfrage tritt in den Controller der Anwendung ein, und Lese-/Schreibvorgänge treten zwischen dem Controller und der Datenzugriffsebene auf. Das Modell wird serialisiert und in der Antwort an den Client zurückgegeben.

Voraussetzungen

Erstellen eines Webprojekts

  • Wählen Sie im Menü "Datei" die Option "Neues Projekt"> aus.
  • Geben Sie die Web-API in das Suchfeld ein.
  • Wählen Sie die Vorlage ASP.NET Core Web API aus , und wählen Sie "Weiter" aus.
  • Benennen Sie im Dialogfeld "Neues Projekt konfigurieren" das Projekt "TodoApi ", und wählen Sie "Weiter" aus.
  • Im Dialogfeld "Zusätzliche Informationen ":
    • Vergewissern Sie sich, dass das Framework.NET 8.0 (Langfristiger Support) ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen für die Verwendung von Controllern (deaktivieren, um minimale APIs zu verwenden) aktiviert ist.
    • Bestätigen Sie, dass das Kontrollkästchen für die OpenAPI-Unterstützung aktiviert ist.
    • Wählen Sie "Erstellen" aus.

Hinzufügen eines NuGet-Pakets

Ein NuGet-Paket muss hinzugefügt werden, um die in diesem Tutorial verwendete Datenbank zu unterstützen.

  • Wählen Sie im Menü "Extras " die Option "NuGet-Paket-Manager > Verwalten von NuGet-Paketen für Lösung" aus.
  • Wählen Sie die Registerkarte " Durchsuchen" aus .
  • Geben Sie Microsoft.EntityFrameworkCore.InMemory in das Suchfeld ein, und wählen Sie Microsoft.EntityFrameworkCore.InMemorydann aus.
  • Aktivieren Sie das Kontrollkästchen "Projekt " im rechten Bereich, und wählen Sie dann "Installieren" aus.

Hinweis

Anleitungen zum Hinzufügen von Paketen zu .NET-Apps finden Sie in den Artikeln unter "Installieren und Verwalten von Paketen" im Workflow "Paketverbrauch" (NuGet-Dokumentation). Bestätigen Sie die richtigen Paketversionen bei NuGet.org.

Testen des Projekts

Die Projektvorlage erstellt eine WeatherForecast API mit Unterstützung für Swagger.

Drücken Sie STRG+F5, um die Ausführung ohne den Debugger zu starten.

Visual Studio zeigt das folgende Dialogfeld an, wenn ein Projekt noch nicht für die Verwendung von SSL konfiguriert ist:

Dieses Projekt ist für die Verwendung von SSL konfiguriert. Um SSL-Warnungen im Browser zu vermeiden, können Sie dem selbstsignierten Zertifikat vertrauen, das IIS Express generiert hat. Möchten Sie dem IIS Express SSL-Zertifikat vertrauen?

Wählen Sie "Ja " aus, wenn Sie dem IIS Express-SSL-Zertifikat vertrauen.

Das folgende Dialogfeld wird angezeigt:

Dialogfeld

Wählen Sie "Ja " aus, wenn Sie dem Entwicklungszertifikat vertrauen möchten.

Informationen zum Vertrauen in den Firefox-Browser finden Sie unter Firefox SEC_ERROR_INADEQUATE_KEY_USAGE-Zertifikatfehler.

Visual Studio startet den Standardbrowser und navigiert zu https://localhost:<port>/swagger/index.html, wobei <port> eine zufällig bei der Projekterstellung festgelegte Portnummer ist.

Die Swagger-Seite /swagger/index.html wird angezeigt. Wählen Sie GET>Try it out>Execute aus. Die Seite zeigt Folgendes an:

  • Der Befehl "Curl ", um die WeatherForecast-API zu testen.
  • Die URL zum Testen der WeatherForecast-API.
  • Der Antwortcode, der Text und die Header.
  • Ein Dropdown-Listenfeld mit Medientypen und dem Beispielwert und -schema.

Wenn die Seite "Swagger" nicht angezeigt wird, lesen Sie dieses GitHub-Problem.

Swagger wird verwendet, um hilfreiche Dokumentation und Hilfeseiten für Web-APIs zu generieren. In diesem Tutorial wird Swagger zum Testen der App verwendet. Weitere Informationen zu Swagger finden Sie in ASP.NET Core Web API-Dokumentation mit Swagger / OpenAPI.

Kopieren Sie die Anforderungs-URL , und fügen Sie sie in den Browser ein: https://localhost:<port>/weatherforecast

Der zurückgegebene JSON-Code sieht in etwa wie das folgende Beispiel aus:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Hinzufügen einer Modellklasse

Ein Modell ist eine Reihe von Klassen, die die von der App verwalteten Daten darstellen. Das Modell für diese App ist die Klasse TodoItem.

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt. Wählen Sie "Neuen Ordner>" aus. Geben Sie dem Ordner den Namen Models.
  • Klicken Sie mit der rechten Maustaste auf den Models Ordner, und wählen Sie "Klasse> aus. Benennen Sie die Klasse TodoItem , und wählen Sie "Hinzufügen" aus.
  • Ersetzen Sie den Vorlagencode durch Folgendes:
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Die Id-Eigenschaft fungiert als eindeutiger Schlüssel in einer relationalen Datenbank.

Modellklassen können überall im Projekt platziert werden, doch gemäß der Konvention wird der Ordner Models verwendet.

Hinzufügen eines Datenbankkontexts

Der Datenbankkontext ist die Hauptklasse, die die Entity Framework-Funktionalität für ein Datenmodell koordiniert. Diese Klasse wird durch Ableiten von der Microsoft.EntityFrameworkCore.DbContext-Klasse erstellt.

  • Klicken Sie mit der rechten Maustaste auf den Models Ordner, und wählen Sie "Klasse> aus. Benennen Sie die Klasse TodoContext , und klicken Sie auf "Hinzufügen".
  • Geben Sie den folgenden Code ein:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models;
    
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }
    
        public DbSet<TodoItem> TodoItems { get; set; } = null!;
    }
    

Registrieren des Datenbankkontexts

In ASP.NET Core müssen Dienste wie der Datenbankkontext im Container der Dependency Injection (DI) registriert werden. Der Container stellt den Dienst für Controller bereit.

Aktualisieren Sie Program.cs mit dem folgenden hervorgehobenen Code:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorangehende Code:

  • Fügt using-Richtlinien hinzu.
  • Fügt dem DI-Container den Datenbankkontext hinzu.
  • Gibt an, dass der Datenbankkontext eine In-Memory Database verwendet

Erstellen eines Controllergerüsts

  • Klicken Sie mit der rechten Maustaste auf den Ordner Controllers.

  • Wählen Sie "Hinzufügen">New Scaffolded Item aus.

  • Wählen Sie API Controller mit Aktionen, mithilfe von Entity Framework, und wählen Sie dann "Hinzufügen" aus.

  • Im Dialogfenster "API-Controller mit Aktionen hinzufügen, unter Verwendung des Entitätsframeworks" :

    • Wählen Sie TodoItem (TodoApi.Models) in der Model-Klasse aus.
    • Wählen Sie TodoContext (TodoApi.Models) in der Data-Kontextklasse aus.
    • Wählen Sie "Hinzufügen" aus.

    Wenn der Gerüstvorgang fehlschlägt, wählen Sie "Hinzufügen" aus, um das Gerüst ein zweites Mal zu versuchen.

Der generierte Code:

  • Markiert die Klasse mit dem [ApiController]-Attribut. Dieses Attribut gibt an, dass der Controller auf Web-API-Anforderungen reagiert. Informationen zu bestimmten Verhaltensweisen, die das Attribut ermöglicht, finden Sie unter Erstellen von Web-APIs mit ASP.NET Core.
  • Verwendet DI, um den Datenbankkontext (TodoContext) in den Controller zu injizieren. Der Datenbankkontext wird in den einzelnen CRUD-Methoden des Controllers verwendet.

Die ASP.NET Core-Vorlagen für:

  • Controller mit Ansichten enthalten [action] in der Routenvorlage.
  • API-Controller enthalten keine [action] in der Routenvorlage.

Wenn das [action] Token nicht in der Routenvorlage enthalten ist, ist der Aktionsname (Methodenname) nicht im Endpunkt enthalten. Dies bedeutet, dass der zugehörige Methodenname der Aktion nicht in der übereinstimmenden Route verwendet wird.

Aktualisieren der PostTodoItem-Erstellungsmethode

Aktualisieren Sie die Rückgabeanweisung in PostTodoItem, um den nameof-Operator zu verwenden.

[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

Der oben stehende Code ist eine HTTP POST-Methode, wie durch das [HttpPost]-Attribut angegeben. Die Methode ruft den Wert von TodoItem aus dem Text der HTTP-Anforderung ab.

Weitere Informationen finden Sie unter Attributrouting mit Http[Verb]-Attributen.

Die CreatedAtAction-Methode:

  • Gibt bei erfolgreicher Ausführung einen HTTP 201-Statuscode zurück. HTTP 201 ist die Standardantwort für eine HTTP POST-Methode, die eine neue Ressource auf dem Server erstellt.
  • Fügt der Antwort einen Location-Header hinzu. Die Location Kopfzeile gibt den URI des neu erstellten to-do Elements an. Weitere Informationen finden Sie unter 10.2.2 2 201 Created.
  • Verweist auf die GetTodoItem-Aktion zum Erstellen des URIs des Location-Headers. Das nameof-Schlüsselwort von C# wird verwendet, um eine Hartcodierung des Aktionsnamens im CreatedAtAction-Aufruf zu vermeiden.

Testen von PostTodoItem

  • Drücken Sie STRG+F5, um die App auszuführen.

  • Wählen Sie im Swagger-Browserfenster POST /api/TodoItems und dann " Ausprobieren" aus.

  • Aktualisieren Sie im Eingabefenster "Anfragekörper" den JSON-Code. Beispiel:

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Wählen Sie "Ausführen" aus.

    Swagger POST

Testen des Adressheader-URIs

Im vorherigen Post zeigt die Swagger-Benutzeroberfläche den Location-Header unter Antwortheader an. Beispiel: location: https://localhost:7260/api/TodoItems/1. Der Standort-Header zeigt den URI für die erstellte Ressource an.

Um den Standort-Header zu testen:

  • Wählen Sie im Swagger-Browserfenster GET /api/TodoItems/{id} und dann " Ausprobieren" aus.

  • Geben Sie 1 in das id Eingabefeld ein, und wählen Sie dann Ausführen aus.

    Swagger GET

Überblick über die GET-Methoden

Zwei GET-Endpunkte werden implementiert:

  • GET /api/todoitems
  • GET /api/todoitems/{id}

Der vorherige Abschnitt veranschaulichte ein Beispiel für die /api/todoitems/{id}-Route.

Folgen Sie den POST-Anweisungen , um ein weiteres Todo-Element hinzuzufügen, und testen Sie dann die /api/todoitems Route mit Swagger.

Diese App verwendet eine In-Memory-Datenbank. Wenn die App angehalten und dann wieder gestartet wird, werden durch die vorherige GET-Anforderung keine Daten zurückgegeben. Wenn keine Daten zurückgegeben werden, senden Sie POST-Daten an die App.

Routing und URL-Pfade

Das [HttpGet]-Attribut gibt eine Methode an, die auf eine HTTP GET-Anforderung antwortet. Der URL-Pfad für jede Methode wird wie folgt erstellt:

  • Beginnen Sie mit der Vorlagenzeichenfolge im Route-Attribut des Controllers:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Ersetzen Sie [controller] durch den Namen des Controllers, bei dem es sich standardmäßig um den Namen der Controller-Klasse ohne das Suffix „Controller“ handelt. Für dieses Beispiel ist der Controllerklassenname TodoItemsController, sodass der Controllername "TodoItems" lautet. ASP.NET Core Routing ist nicht groß-/kleinschreibungssensitiv.

  • Wenn das [HttpGet]-Attribut eine Routenvorlage (z. B. [HttpGet("products")]) hat, fügen Sie diese an den Pfad an. In diesem Beispiel wird keine Vorlage verwendet. Weitere Informationen finden Sie unter Attributrouting mit Http[Verb]-Attributen.

In der folgenden GetTodoItem-Methode ist "{id}" eine Platzhaltervariable für den eindeutigen Bezeichner des To-do-Elements. Wenn GetTodoItem aufgerufen wird, wird der Methode in ihrem Parameter "{id}" der Wert von id aus der URL bereitgestellt.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Rückgabewerte

Der Rückgabetyp der GetTodoItems- und GetTodoItem-Methoden ist vom ActionResult<T>-Typ. ASP.NET Core serialisiert das Objekt automatisch in JSON und schreibt den JSON-Code in den Textkörper der Antwortnachricht. Der Antwortcode für diesen Rückgabetyp ist 200 OK, vorausgesetzt, es gibt keine unbehandelten Ausnahmen. Nicht behandelte Ausnahmen werden in 5xx-Fehler übersetzt.

ActionResult-Rückgabetypen können eine Vielzahl von HTTP-Statuscodes darstellen. Beispielsweise kann GetTodoItem zwei verschiedene Statuswerte zurückgeben:

  • Wenn kein Element mit der angeforderten ID übereinstimmt, gibt die Methode den Fehlercode 404 zurückNotFound .
  • Andernfalls gibt die Methode 200 mit einem JSON-Antworttext zurück. Die Rückgabe von item löst eine HTTP 200-Antwort aus.

PutTodoItem-Methode

Untersuchen Sie die PutTodoItem-Methode.

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem ähnelt PostTodoItem, verwendet allerdings HTTP PUT. Die Antwort lautet 204 (Kein Inhalt). Gemäß der HTTP-Spezifikation erfordert eine PUT-Anforderung, dass der Client die gesamte aktualisierte Entität (nicht nur die Änderungen) sendet. Verwenden Sie HTTP PATCH, um Teilupdates zu unterstützen.

Testen der PutTodoItem-Methode

In diesem Beispiel wird eine In-Memory-Datenbank verwendet, die jedes Mal initialisiert werden muss, wenn die App gestartet wird. Es muss ein Element in der Datenbank vorhanden sein, bevor Sie einen PUT-Aufruf durchführen. Rufen Sie vor einem PUT-Aufruf GET auf, um sicherzustellen, dass ein Element in der Datenbank vorhanden ist.

Verwenden Sie in der Swagger-Benutzeroberfläche die PUT-Schaltfläche, um das TodoItem-Element mit der ID = 1 zu aktualisieren und seinen Namen auf "feed fish" festzulegen. Beachten Sie, dass die Antwort HTTP 204 No Content lautet.

Die DeleteTodoItem-Methode

Untersuchen Sie die DeleteTodoItem-Methode.

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

Testen der DeleteTodoItem-Methode

Verwenden Sie die Benutzeroberfläche von Swagger, um das TodoItem-Element mit der ID = 1 zu löschen. Beachten Sie, dass die Antwort HTTP 204 No Content lautet.

Testen mit anderen Tools

Es gibt viele andere Tools, die zum Testen von Web-APIs verwendet werden können, z. B.:

Weitere Informationen finden Sie unter

Vermeiden von Overposting

Derzeit macht die Beispiel-App das gesamte TodoItem-Objekt verfügbar. In den Produktions-Apps sind die Daten, die eingegeben und mithilfe einer Teilmenge des Modells zurückgegeben werden, in der Regel eingeschränkt. Hierfür gibt es mehrere Gründe, wobei die Sicherheit einer der Hauptgründe ist. Die Teilmenge eines Modells wird üblicherweise als Datenübertragungsobjekt (DTO, Data Transfer Object), Eingabemodell oder Anzeigemodell bezeichnet. DTO wird in diesem Lernprogramm verwendet.

Ein DTO kann für Folgendes verwendet werden:

  • Vermeiden Sie Overposting.
  • Eigenschaften ausblenden, die Kunden nicht sehen sollen.
  • Auslassen einiger Eigenschaften, um die Nutzlast zu verringern
  • Vereinfachen von Objektgraphen, die geschachtelte Objekte enthalten Vereinfachte Objektgraphen können für Clients zweckmäßiger sein.

Um den DTO-Ansatz zu veranschaulichen, aktualisieren Sie die TodoItem-Klasse, sodass sie ein geheimes Feld einschließt:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string? Name { get; set; }
        public bool IsComplete { get; set; }
        public string? Secret { get; set; }
    }
}

Das geheime Feld muss in dieser App ausgeblendet werden, eine administrative App kann es jedoch verfügbar machen.

Vergewissern Sie sich, dass Sie das geheime Feld veröffentlichen und abrufen können.

Erstellen Sie ein DTO-Modell:

namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Aktualisieren Sie TodoItemsController, sodass TodoItemDTO verwendet wird:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/TodoItems
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    // GET: api/TodoItems/5
    // <snippet_GetByID>
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }
    // </snippet_GetByID>

    // PUT: api/TodoItems/5
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Update>
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
    {
        if (id != todoDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoDTO.Name;
        todoItem.IsComplete = todoDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }
    // </snippet_Update>

    // POST: api/TodoItems
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Create>
    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoDTO.IsComplete,
            Name = todoDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }
    // </snippet_Create>

    // DELETE: api/TodoItems/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id)
    {
        return _context.TodoItems.Any(e => e.Id == id);
    }

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
       new TodoItemDTO
       {
           Id = todoItem.Id,
           Name = todoItem.Name,
           IsComplete = todoItem.IsComplete
       };
}

Vergewissern Sie sich, dass Sie das geheime Feld weder veröffentlichen noch abrufen können.

Aufrufen der Web-API mit JavaScript

Siehe Lernprogramm: Aufrufen einer ASP.NET Core-Web-API mit JavaScript.

Videoreihe zur Web-API

Siehe Video: Anfängerserie zu: Web-APIs.

Enterprise Web App-Muster

Anleitungen zum Erstellen einer zuverlässigen, sicheren, leistungsfähigen, testbaren und skalierbaren ASP.NET Core-App finden Sie unter Enterprise Web App-Muster. Eine vollständige Beispielweb-App zur Produktionsqualität, die die Muster implementiert, ist verfügbar.

Hinzufügen der Authentifizierungsunterstützung zu einer Web-API

ASP.NET Core Identity fügt Benutzeroberflächen-Anmeldefunktionen zu ASP.NET Core-Web-Apps hinzu. Verwenden Sie zum Sichern von Web-APIs und SPAs eine der folgenden Optionen:

Duende Identity Server ist ein OpenID Connect- und OAuth 2.0-Framework für ASP.NET Core. Duende Identity Server ermöglicht die folgenden Sicherheitsfeatures:

  • Authentifizierung als Dienst
  • Einmaliges Anmelden und einmaliges Abmelden für mehrere Anwendungstypen
  • Zugriffssteuerung für APIs
  • Föderationsgateway

Wichtig

Duende Software erfordert möglicherweise, dass Sie eine Lizenzgebühr für die Produktionsnutzung von Duende Identity Server bezahlen. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core in .NET 5 zu .NET 6.

Weitere Informationen finden Sie in der Duende Server-Dokumentation (Duende Identity Software-Website).

Veröffentlichen in Azure

Informationen zum Bereitstellen in Azure finden Sie in der Schnellstartanleitung: Bereitstellen einer ASP.NET Web-App.

Zusätzliche Ressourcen

Beispielcode für dieses Lernprogramm anzeigen oder herunterladen. Hier erfahren Sie, wie Sie herunterladen.

Weitere Informationen finden Sie in den folgenden Ressourcen:

In diesem Tutorial lernen Sie die Grundlagen der Erstellung einer controllerbasierten Web-API, die eine Datenbank verwendet. Ein weiterer Ansatz zum Erstellen von APIs in ASP.NET Core besteht darin, minimale APIs zu erstellen. Hilfe bei der Auswahl zwischen minimalen APIs und controllerbasierten APIs finden Sie in der Übersicht über APIs. Ein Lernprogramm zum Erstellen einer minimalen API finden Sie im Lernprogramm: Erstellen einer minimalen API mit ASP.NET Core.

Übersicht

In diesem Tutorial wird die folgende API erstellt:

Programmierschnittstelle (API) Beschreibung Anforderungstext Antworttext
GET /api/todoitems Alle To-do-Elemente abrufen Keine Array von To-do-Elementen
GET /api/todoitems/{id} Ein Element nach ID abrufen Keine Aufgabenpunkt
POST /api/todoitems Neues Element hinzufügen Aufgabenpunkt Aufgabenpunkt
PUT /api/todoitems/{id} Vorhandenes Element aktualisieren Aufgabenpunkt Keine
DELETE /api/todoitems/{id}     Löschen eines Elements Keine Keine

Das folgende Diagramm zeigt den Entwurf der App.

Der Client wird durch ein Feld auf der linken Seite dargestellt. Er sendet eine Anfrage und empfängt eine Antwort von der Anwendung, ein Feld, das auf der rechten Seite gezeichnet wird. Innerhalb des Anwendungsfeldes stellen drei Felder den Controller, das Modell und die Datenzugriffsebene dar. Die Anfrage tritt in den Controller der Anwendung ein, und Lese-/Schreibvorgänge treten zwischen dem Controller und der Datenzugriffsebene auf. Das Modell wird serialisiert und in der Antwort an den Client zurückgegeben.

Voraussetzungen

Erstellen eines Webprojekts

  • Wählen Sie im Menü "Datei" die Option "Neues Projekt"> aus.
  • Geben Sie die Web-API in das Suchfeld ein.
  • Wählen Sie die Vorlage ASP.NET Core Web API aus , und wählen Sie "Weiter" aus.
  • Benennen Sie im Dialogfeld "Neues Projekt konfigurieren" das Projekt "TodoApi ", und wählen Sie "Weiter" aus.
  • Im Dialogfeld "Zusätzliche Informationen ":
    • Vergewissern Sie sich, dass das Framework.NET 8.0 (Langfristiger Support) ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen für die Verwendung von Controllern (deaktivieren, um minimale APIs zu verwenden) aktiviert ist.
    • Bestätigen Sie, dass das Kontrollkästchen für die OpenAPI-Unterstützung aktiviert ist.
    • Wählen Sie "Erstellen" aus.

Hinzufügen eines NuGet-Pakets

Ein NuGet-Paket muss hinzugefügt werden, um die in diesem Tutorial verwendete Datenbank zu unterstützen.

  • Wählen Sie im Menü "Extras " die Option "NuGet-Paket-Manager > Verwalten von NuGet-Paketen für Lösung" aus.
  • Wählen Sie die Registerkarte " Durchsuchen" aus .
  • Geben Sie Microsoft.EntityFrameworkCore.InMemory in das Suchfeld ein, und wählen Sie Microsoft.EntityFrameworkCore.InMemorydann aus.
  • Aktivieren Sie das Kontrollkästchen "Projekt " im rechten Bereich, und wählen Sie dann "Installieren" aus.

Hinweis

Anleitungen zum Hinzufügen von Paketen zu .NET-Apps finden Sie in den Artikeln unter "Installieren und Verwalten von Paketen" im Workflow "Paketverbrauch" (NuGet-Dokumentation). Bestätigen Sie die richtigen Paketversionen bei NuGet.org.

Testen des Projekts

Die Projektvorlage erstellt eine WeatherForecast API mit Unterstützung für Swagger.

Drücken Sie STRG+F5, um die Ausführung ohne den Debugger zu starten.

Visual Studio zeigt das folgende Dialogfeld an, wenn ein Projekt noch nicht für die Verwendung von SSL konfiguriert ist:

Dieses Projekt ist für die Verwendung von SSL konfiguriert. Um SSL-Warnungen im Browser zu vermeiden, können Sie dem selbstsignierten Zertifikat vertrauen, das IIS Express generiert hat. Möchten Sie dem IIS Express SSL-Zertifikat vertrauen?

Wählen Sie "Ja " aus, wenn Sie dem IIS Express-SSL-Zertifikat vertrauen.

Das folgende Dialogfeld wird angezeigt:

Dialogfeld

Wählen Sie "Ja " aus, wenn Sie dem Entwicklungszertifikat vertrauen möchten.

Informationen zum Vertrauen in den Firefox-Browser finden Sie unter Firefox SEC_ERROR_INADEQUATE_KEY_USAGE-Zertifikatfehler.

Visual Studio startet den Standardbrowser und navigiert zu https://localhost:<port>/swagger/index.html, wobei <port> eine zufällig bei der Projekterstellung festgelegte Portnummer ist.

Die Swagger-Seite /swagger/index.html wird angezeigt. Wählen Sie GET>Try it out>Execute aus. Die Seite zeigt Folgendes an:

  • Der Befehl "Curl ", um die WeatherForecast-API zu testen.
  • Die URL zum Testen der WeatherForecast-API.
  • Der Antwortcode, der Text und die Header.
  • Ein Dropdown-Listenfeld mit Medientypen und dem Beispielwert und -schema.

Wenn die Seite "Swagger" nicht angezeigt wird, lesen Sie dieses GitHub-Problem.

Swagger wird verwendet, um hilfreiche Dokumentation und Hilfeseiten für Web-APIs zu generieren. In diesem Tutorial wird Swagger zum Testen der App verwendet. Weitere Informationen zu Swagger finden Sie in ASP.NET Core Web API-Dokumentation mit Swagger / OpenAPI.

Kopieren Sie die Anforderungs-URL , und fügen Sie sie in den Browser ein: https://localhost:<port>/weatherforecast

Der zurückgegebene JSON-Code sieht in etwa wie das folgende Beispiel aus:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Hinzufügen einer Modellklasse

Ein Modell ist eine Reihe von Klassen, die die von der App verwalteten Daten darstellen. Das Modell für diese App ist die Klasse TodoItem.

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt. Wählen Sie "Neuen Ordner>" aus. Geben Sie dem Ordner den Namen Models.
  • Klicken Sie mit der rechten Maustaste auf den Models Ordner, und wählen Sie "Klasse> aus. Benennen Sie die Klasse TodoItem , und wählen Sie "Hinzufügen" aus.
  • Ersetzen Sie den Vorlagencode durch Folgendes:
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Die Id-Eigenschaft fungiert als eindeutiger Schlüssel in einer relationalen Datenbank.

Modellklassen können überall im Projekt platziert werden, doch gemäß der Konvention wird der Ordner Models verwendet.

Hinzufügen eines Datenbankkontexts

Der Datenbankkontext ist die Hauptklasse, die die Entity Framework-Funktionalität für ein Datenmodell koordiniert. Diese Klasse wird durch Ableiten von der Microsoft.EntityFrameworkCore.DbContext-Klasse erstellt.

  • Klicken Sie mit der rechten Maustaste auf den Models Ordner, und wählen Sie "Klasse> aus. Benennen Sie die Klasse TodoContext , und klicken Sie auf "Hinzufügen".
  • Geben Sie den folgenden Code ein:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models;
    
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }
    
        public DbSet<TodoItem> TodoItems { get; set; } = null!;
    }
    

Registrieren des Datenbankkontexts

In ASP.NET Core müssen Dienste wie der Datenbankkontext im Container der Dependency Injection (DI) registriert werden. Der Container stellt den Dienst für Controller bereit.

Aktualisieren Sie Program.cs mit dem folgenden hervorgehobenen Code:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Der vorangehende Code:

  • Fügt using-Richtlinien hinzu.
  • Fügt dem DI-Container den Datenbankkontext hinzu.
  • Gibt an, dass der Datenbankkontext eine In-Memory Database verwendet

Erstellen eines Controllergerüsts

  • Klicken Sie mit der rechten Maustaste auf den Ordner Controllers.

  • Wählen Sie "Hinzufügen">New Scaffolded Item aus.

  • Wählen Sie API Controller mit Aktionen, mithilfe von Entity Framework, und wählen Sie dann "Hinzufügen" aus.

  • Im Dialogfenster "API-Controller mit Aktionen hinzufügen, unter Verwendung des Entitätsframeworks" :

    • Wählen Sie TodoItem (TodoApi.Models) in der Model-Klasse aus.
    • Wählen Sie TodoContext (TodoApi.Models) in der Data-Kontextklasse aus.
    • Wählen Sie "Hinzufügen" aus.

    Wenn der Gerüstvorgang fehlschlägt, wählen Sie "Hinzufügen" aus, um das Gerüst ein zweites Mal zu versuchen.

Der generierte Code:

  • Markiert die Klasse mit dem [ApiController]-Attribut. Dieses Attribut gibt an, dass der Controller auf Web-API-Anforderungen reagiert. Informationen zu bestimmten Verhaltensweisen, die das Attribut ermöglicht, finden Sie unter Erstellen von Web-APIs mit ASP.NET Core.
  • Verwendet DI, um den Datenbankkontext (TodoContext) in den Controller zu injizieren. Der Datenbankkontext wird in den einzelnen CRUD-Methoden des Controllers verwendet.

Die ASP.NET Core-Vorlagen für:

  • Controller mit Ansichten enthalten [action] in der Routenvorlage.
  • API-Controller enthalten keine [action] in der Routenvorlage.

Wenn das [action] Token nicht in der Routenvorlage enthalten ist, ist der Aktionsname (Methodenname) nicht im Endpunkt enthalten. Dies bedeutet, dass der zugehörige Methodenname der Aktion nicht in der übereinstimmenden Route verwendet wird.

Aktualisieren der PostTodoItem-Erstellungsmethode

Aktualisieren Sie die Rückgabeanweisung in PostTodoItem, um den nameof-Operator zu verwenden.

[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

Der oben stehende Code ist eine HTTP POST-Methode, wie durch das [HttpPost]-Attribut angegeben. Die Methode ruft den Wert von TodoItem aus dem Text der HTTP-Anforderung ab.

Weitere Informationen finden Sie unter Attributrouting mit Http[Verb]-Attributen.

Die CreatedAtAction-Methode:

  • Gibt bei erfolgreicher Ausführung einen HTTP 201-Statuscode zurück. HTTP 201 ist die Standardantwort für eine HTTP POST-Methode, die eine neue Ressource auf dem Server erstellt.
  • Fügt der Antwort einen Location-Header hinzu. Die Location Kopfzeile gibt den URI des neu erstellten to-do Elements an. Weitere Informationen finden Sie unter 10.2.2 2 201 Created.
  • Verweist auf die GetTodoItem-Aktion zum Erstellen des URIs des Location-Headers. Das nameof-Schlüsselwort von C# wird verwendet, um eine Hartcodierung des Aktionsnamens im CreatedAtAction-Aufruf zu vermeiden.

Testen von PostTodoItem

  • Drücken Sie STRG+F5, um die App auszuführen.

  • Wählen Sie im Swagger-Browserfenster POST /api/TodoItems und dann " Ausprobieren" aus.

  • Aktualisieren Sie im Eingabefenster "Anfragekörper" den JSON-Code. Beispiel:

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Wählen Sie "Ausführen" aus.

    Swagger POST

Testen des Adressheader-URIs

Im vorherigen Post zeigt die Swagger-Benutzeroberfläche den Location-Header unter Antwortheader an. Beispiel: location: https://localhost:7260/api/TodoItems/1. Der Standort-Header zeigt den URI für die erstellte Ressource an.

Um den Standort-Header zu testen:

  • Wählen Sie im Swagger-Browserfenster GET /api/TodoItems/{id} und dann " Ausprobieren" aus.

  • Geben Sie 1 in das id Eingabefeld ein, und wählen Sie dann Ausführen aus.

    Swagger GET

Überblick über die GET-Methoden

Zwei GET-Endpunkte werden implementiert:

  • GET /api/todoitems
  • GET /api/todoitems/{id}

Der vorherige Abschnitt veranschaulichte ein Beispiel für die /api/todoitems/{id}-Route.

Folgen Sie den POST-Anweisungen , um ein weiteres Todo-Element hinzuzufügen, und testen Sie dann die /api/todoitems Route mit Swagger.

Diese App verwendet eine In-Memory-Datenbank. Wenn die App angehalten und dann wieder gestartet wird, werden durch die vorherige GET-Anforderung keine Daten zurückgegeben. Wenn keine Daten zurückgegeben werden, senden Sie POST-Daten an die App.

Routing und URL-Pfade

Das [HttpGet]-Attribut gibt eine Methode an, die auf eine HTTP GET-Anforderung antwortet. Der URL-Pfad für jede Methode wird wie folgt erstellt:

  • Beginnen Sie mit der Vorlagenzeichenfolge im Route-Attribut des Controllers:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Ersetzen Sie [controller] durch den Namen des Controllers, bei dem es sich standardmäßig um den Namen der Controller-Klasse ohne das Suffix „Controller“ handelt. Für dieses Beispiel ist der Controllerklassenname TodoItemsController, sodass der Controllername "TodoItems" lautet. ASP.NET Core Routing ist nicht groß-/kleinschreibungssensitiv.

  • Wenn das [HttpGet]-Attribut eine Routenvorlage (z. B. [HttpGet("products")]) hat, fügen Sie diese an den Pfad an. In diesem Beispiel wird keine Vorlage verwendet. Weitere Informationen finden Sie unter Attributrouting mit Http[Verb]-Attributen.

In der folgenden GetTodoItem-Methode ist "{id}" eine Platzhaltervariable für den eindeutigen Bezeichner des To-do-Elements. Wenn GetTodoItem aufgerufen wird, wird der Methode in ihrem Parameter "{id}" der Wert von id aus der URL bereitgestellt.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Rückgabewerte

Der Rückgabetyp der GetTodoItems- und GetTodoItem-Methoden ist vom ActionResult<T>-Typ. ASP.NET Core serialisiert das Objekt automatisch in JSON und schreibt den JSON-Code in den Textkörper der Antwortnachricht. Der Antwortcode für diesen Rückgabetyp ist 200 OK, vorausgesetzt, es gibt keine unbehandelten Ausnahmen. Nicht behandelte Ausnahmen werden in 5xx-Fehler übersetzt.

ActionResult-Rückgabetypen können eine Vielzahl von HTTP-Statuscodes darstellen. Beispielsweise kann GetTodoItem zwei verschiedene Statuswerte zurückgeben:

  • Wenn kein Element mit der angeforderten ID übereinstimmt, gibt die Methode den Fehlercode 404 zurückNotFound .
  • Andernfalls gibt die Methode 200 mit einem JSON-Antworttext zurück. Die Rückgabe von item löst eine HTTP 200-Antwort aus.

PutTodoItem-Methode

Untersuchen Sie die PutTodoItem-Methode.

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem ähnelt PostTodoItem, verwendet allerdings HTTP PUT. Die Antwort lautet 204 (Kein Inhalt). Gemäß der HTTP-Spezifikation erfordert eine PUT-Anforderung, dass der Client die gesamte aktualisierte Entität (nicht nur die Änderungen) sendet. Verwenden Sie HTTP PATCH, um Teilupdates zu unterstützen.

Testen der PutTodoItem-Methode

In diesem Beispiel wird eine In-Memory-Datenbank verwendet, die jedes Mal initialisiert werden muss, wenn die App gestartet wird. Es muss ein Element in der Datenbank vorhanden sein, bevor Sie einen PUT-Aufruf durchführen. Rufen Sie vor einem PUT-Aufruf GET auf, um sicherzustellen, dass ein Element in der Datenbank vorhanden ist.

Verwenden Sie in der Swagger-Benutzeroberfläche die PUT-Schaltfläche, um das TodoItem-Element mit der ID = 1 zu aktualisieren und seinen Namen auf "feed fish" festzulegen. Beachten Sie, dass die Antwort HTTP 204 No Content lautet.

Die DeleteTodoItem-Methode

Untersuchen Sie die DeleteTodoItem-Methode.

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

Testen der DeleteTodoItem-Methode

Verwenden Sie die Benutzeroberfläche von Swagger, um das TodoItem-Element mit der ID = 1 zu löschen. Beachten Sie, dass die Antwort HTTP 204 No Content lautet.

Testen mit anderen Tools

Es gibt viele andere Tools, die zum Testen von Web-APIs verwendet werden können, z. B.:

Weitere Informationen finden Sie unter

Vermeiden von Overposting

Derzeit macht die Beispiel-App das gesamte TodoItem-Objekt verfügbar. In den Produktions-Apps sind die Daten, die eingegeben und mithilfe einer Teilmenge des Modells zurückgegeben werden, in der Regel eingeschränkt. Hierfür gibt es mehrere Gründe, wobei die Sicherheit einer der Hauptgründe ist. Die Teilmenge eines Modells wird üblicherweise als Datenübertragungsobjekt (DTO, Data Transfer Object), Eingabemodell oder Anzeigemodell bezeichnet. DTO wird in diesem Lernprogramm verwendet.

Ein DTO kann für Folgendes verwendet werden:

  • Vermeiden Sie Overposting.
  • Eigenschaften ausblenden, die Kunden nicht sehen sollen.
  • Auslassen einiger Eigenschaften, um die Nutzlast zu verringern
  • Vereinfachen von Objektgraphen, die geschachtelte Objekte enthalten Vereinfachte Objektgraphen können für Clients zweckmäßiger sein.

Um den DTO-Ansatz zu veranschaulichen, aktualisieren Sie die TodoItem-Klasse, sodass sie ein geheimes Feld einschließt:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string? Name { get; set; }
        public bool IsComplete { get; set; }
        public string? Secret { get; set; }
    }
}

Das geheime Feld muss in dieser App ausgeblendet werden, eine administrative App kann es jedoch verfügbar machen.

Vergewissern Sie sich, dass Sie das geheime Feld veröffentlichen und abrufen können.

Erstellen Sie ein DTO-Modell:

namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Aktualisieren Sie TodoItemsController, sodass TodoItemDTO verwendet wird:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/TodoItems
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    // GET: api/TodoItems/5
    // <snippet_GetByID>
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }
    // </snippet_GetByID>

    // PUT: api/TodoItems/5
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Update>
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
    {
        if (id != todoDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoDTO.Name;
        todoItem.IsComplete = todoDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }
    // </snippet_Update>

    // POST: api/TodoItems
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Create>
    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoDTO.IsComplete,
            Name = todoDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }
    // </snippet_Create>

    // DELETE: api/TodoItems/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id)
    {
        return _context.TodoItems.Any(e => e.Id == id);
    }

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
       new TodoItemDTO
       {
           Id = todoItem.Id,
           Name = todoItem.Name,
           IsComplete = todoItem.IsComplete
       };
}

Vergewissern Sie sich, dass Sie das geheime Feld weder veröffentlichen noch abrufen können.

Aufrufen der Web-API mit JavaScript

Siehe Lernprogramm: Aufrufen einer ASP.NET Core-Web-API mit JavaScript.

Videoreihe zur Web-API

Siehe Video: Anfängerserie zu: Web-APIs.

Enterprise Web App-Muster

Anleitungen zum Erstellen einer zuverlässigen, sicheren, leistungsfähigen, testbaren und skalierbaren ASP.NET Core-App finden Sie unter Enterprise Web App-Muster. Eine vollständige Beispielweb-App zur Produktionsqualität, die die Muster implementiert, ist verfügbar.

Hinzufügen der Authentifizierungsunterstützung zu einer Web-API

ASP.NET Core Identity fügt Benutzeroberflächen-Anmeldefunktionen zu ASP.NET Core-Web-Apps hinzu. Verwenden Sie zum Sichern von Web-APIs und SPAs eine der folgenden Optionen:

Duende Identity Server ist ein OpenID Connect- und OAuth 2.0-Framework für ASP.NET Core. Duende Identity Server ermöglicht die folgenden Sicherheitsfeatures:

  • Authentifizierung als Dienst
  • Einmaliges Anmelden und einmaliges Abmelden für mehrere Anwendungstypen
  • Zugriffssteuerung für APIs
  • Föderationsgateway

Wichtig

Duende Software erfordert möglicherweise, dass Sie eine Lizenzgebühr für die Produktionsnutzung von Duende Identity Server bezahlen. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core in .NET 5 zu .NET 6.

Weitere Informationen finden Sie in der Duende Server-Dokumentation (Duende Identity Software-Website).

Veröffentlichen in Azure

Informationen zum Bereitstellen in Azure finden Sie in der Schnellstartanleitung: Bereitstellen einer ASP.NET Web-App.

Zusätzliche Ressourcen

Beispielcode für dieses Lernprogramm anzeigen oder herunterladen. Hier erfahren Sie, wie Sie herunterladen.

Weitere Informationen finden Sie in den folgenden Ressourcen: