Tutorial: Erstellen einer 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 Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-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 Rick Anderson und Kirk Larkin

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

Übersicht

In diesem Tutorial wird die folgende API erstellt:

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 To-do-Element
POST /api/todoitems Neues Element hinzufügen To-do-Element To-do-Element
PUT /api/todoitems/{id} Vorhandenes Element aktualisieren To-do-Element Keine
DELETE /api/todoitems/{id}     Löschen eines Elements Keine Keine

Das folgende Diagramm zeigt den Entwurf der App.

Der Client wird durch ein Rechteck auf der linken Seite dargestellt. Er sendet eine Anforderung und erhält eine Antwort von der Anwendung, die in einem Rechteck auf der rechten Seite dargestellt ist. Innerhalb des Anwendungsrechtecks stellen drei Rechtecke den Controller, das Modell und die Datenzugriffsschicht dar. Die Anforderung kommt im Controller der Anwendung an, und Lese-/Schreibvorgänge finden zwischen dem Controller und der Datenzugriffsschicht statt. Das Modell wird serialisiert und in der Antwort an den Client zurückgegeben.

Voraussetzungen

Erstellen eines Webprojekts

  • Klicken Sie im Menü Datei auf Neu>Projekt.
  • Geben Sie Web-API in das Suchfeld ein.
  • Wählen Sie die ASP.NET Core-Web-API-Vorlage aus, und klicken Sie auf Weiter.
  • Geben Sie im Dialogfeld Neues Projekt konfigurieren dem Projekt den Namen TodoApi, und wählen Sie dann Weiter aus.
  • Im Dialogfeld Zusätzliche Informationen:
    • Bestätigen Sie, dass das Framework auf .NET 8.0 (Langfristiger Support) festgelegt ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen Controller verwenden (zur Verwendung minimaler APIs deaktivieren) aktiviert ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen OpenAPI-Unterstützung aktivieren aktiviert ist.
    • Klicken Sie auf Erstellen.

Hinzufügen eines NuGet-Pakets

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

  • Klicken Sie im Menü Extras auf NuGet-Paket-Manager > NuGet-Pakete für Projektmappe verwalten.
  • Wählen Sie die Registerkarte Durchsuchen aus.
  • Geben Sie Microsoft.EntityFrameworkCore.InMemory in das Suchfeld ein, und wählen Sie Microsoft.EntityFrameworkCore.InMemory aus.
  • Aktivieren Sie das Kontrollkästchen Projekt im rechten Bereich, und klicken Sie dann auf Installieren.

Hinweis

Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.

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 SSL-Zertifikat von IIS Express vertrauen?

Wählen Sie Ja aus, wenn Sie dem IIS Express-SLL-Zertifikat vertrauen möchten.

Das folgende Dialogfeld wird angezeigt:

Dialogfeld „Sicherheitswarnung“

Klicken Sie auf Ja, wenn Sie zustimmen möchten, dass das Entwicklungszertifikat vertrauenswürdig ist.

Informationen dazu, wie Sie dem Firefox-Browser vertrauen, finden Sie unter Firefox-Zertifikatfehler SEC_ERROR_INADEQUATE_KEY_USAGE.

Visual Studio startet einen Standardbrowser und navigiert zu https://localhost:<port>/swagger/index.html, wobei es sich bei <port> um eine zufällig ausgewählte Portnummer handelt.

Die Swagger-Seite /swagger/index.html wird angezeigt. Wählen Sie GET>Tryit out>Execute (GET > Testen> Ausführen) aus. Die Seite zeigt Folgendes an:

  • Der Curl-Befehl, zum Testen der WeatherForecast-API.
  • 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 Swagger-Seite nicht angezeigt wird, finden Sie weitere Informationen in diesem GitHub-Issue.

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 im 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 Gruppe von Klassen, die die Daten darstellen, die die App verwaltet. Das Modell für diese App ist die Klasse TodoItem.

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt. Klicken Sie auf Hinzufügen>Neuer Ordner. Geben Sie dem Ordner den Namen Modelsanmelden.
  • Klicken Sie mit der rechten Maustaste auf den Ordner Models, und wählen Sie Hinzufügen>Klasse aus. Nennen 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-Funktionen 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 Ordner Models, und wählen Sie Hinzufügen>Klasse aus. Nennen 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 mit dem Container Abhängigkeitsinjektion 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 Abhängigkeitscontainer 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.

  • Klicken Sie auf API-Controller mit Aktionen unter Verwendung von Entity Framework und dann auf Hinzufügen.

  • Führen Sie im Dialogfeld API-Controller mit Aktionen unter Verwendung von Entity Framework folgende Schritte aus:

    • Wählen Sie in der Modellklasse das Element TodoItem (TodoApi.Models) aus.
    • Wählen Sie in der Datenkontextklasse das Element TodoContext (TodoApi.Models) aus.
    • Wählen Sie Hinzufügen aus.

    Wenn beim Gerüstbauvorgang ein Fehler auftritt, wählen Sie Hinzufügen aus, um ein zweites Mal den Gerüstbau zu versuchen.

Der generierte Code hat folgende Auswirkungen:

  • Markiert die Klasse mit dem [ApiController]-Attribut. Dieses Attribut gibt an, dass der Controller auf Web-API-Anforderungen reagiert. Informationen über bestimmte Verhaltensweisen, die das Attribut aktivieren, finden Sie unter Erstellen von Web-APIs mit ASP.NET Core.
  • Verwendet die Abhängigkeitsinjektion, um den Datenbankkontext (TodoContext) dem Controller hinzuzufügen. Der Datenbankkontext wird in den einzelnen CRUD-Methoden im Controller 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 sich das [action]-Token nicht in der Routenvorlage befindet, 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 mit dem nameof-Operator:

[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 Erfolg den HTTP-Statuscode 201 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. Der Location-Header legt den URI des neu erstellten To-do-Elements fest. Weitere Informationen finden Sie unter 10.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 Try it out aus.

  • Aktualisieren Sie im Eingabefenster Anforderungstext das JSON. Beispiel:

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Wählen Sie Execute.

    Swagger POST

Testen des Adressheader-URIs

In der vorstehenden POST zeigt die Swagger-Benutzeroberfläche den Adressheader unter Response Headers an. Beispiel: location: https://localhost:7260/api/TodoItems/1. Der Adressheader zeigt den URI für die erstellte Ressource an.

Testen des Adressheaders:

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

  • Geben Sie 1 in das Eingabefeld id ein, und wählen Sie dann Execute 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 mit 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. In diesem Beispiel ist der Klassenname des Controllers „TodoItemsController“. Der Controllername lautet also „TodoItems“. Beim ASP.NET Core-Routing wird die Groß-/Kleinschreibung nicht beachtet.

  • 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 Wert von "{id}" in der URL der Methode in ihrem Parameter id 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 Methoden GetTodoItems und GetTodoItem ist ActionResult<T>-Typ . ASP.NET Core serialisiert automatisch das Objekt in JSON und schreibt den JSON-Code in den Text der Antwortnachricht. Der Antwortcode für diesen Rückgabetyp ist 200 OK, vorausgesetzt, es gibt keine Ausnahmefehler. 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 einen NotFound-Fehlercode Status 404 zurück.
  • 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 ist 204 (No Content). 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.

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. In diesem Tutorial wird DTO verwendet.

Ein DTO kann für Folgendes verwendet werden:

  • Vermeiden Sie Overposting.
  • Ausblenden von Eigenschaften, die Clients nicht anzeigen 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

Mehr dazu finden Sie im -Tutorial: Aufrufen einer ASP.NET Core-Web-API mit JavaScript.

Videoreihe zur Web-API

Sehen Sie sich das Video: Einsteigerreihe: Web-APIs an.

Zuverlässige Web-App-Muster

Einen Leitfaden zum Erstellen einer modernen, zuverlässigen, leistungsfähigen, testbaren, kosteneffizienten und skalierbaren ASP.NET Core-App finden Sie in den YouTube-Videos und im Artikel zum zuverlässigen Web-App-Muster für .NET – ganz gleich, ob Sie eine App von Grund auf neu erstellen oder umgestalten möchten.

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
  • Federation Gateway

Wichtig

Duende Software erhebt ggf. eine Lizenzgebühr für die Nutzung von Duende Identity Server in der Produktion. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core 5.0 zu 6.0.

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

Veröffentlichen in Azure

Weitere Informationen zur Bereistellung in Azure finden Sie unter Schnellstart: Bereitstellen einer ASP.NET-Web-App.

Zusätzliche Ressourcen

Sie können den Beispielcode für dieses Tutorial anzeigen oder herunterladen. Informationen zum Herunterladen finden Sie hier.

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 anderer Ansatz zum Erstellen von APIs in ASP.NET Core besteht in der Erstellung von minimalen APIs. Hilfe bei der Entscheidung zwischen minimalen APIs und controllerbasierten APIs finden Sie in der Übersicht über APIs. Anleitungen zum Erstellen einer minimalen API finden Sie im Tutorial: Erstellen einer minimalen API mit ASP.NET Core.

Übersicht

In diesem Tutorial wird die folgende API erstellt:

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 To-do-Element
POST /api/todoitems Neues Element hinzufügen To-do-Element To-do-Element
PUT /api/todoitems/{id} Vorhandenes Element aktualisieren To-do-Element Keine
DELETE /api/todoitems/{id}     Löschen eines Elements Keine Keine

Das folgende Diagramm zeigt den Entwurf der App.

Der Client wird durch ein Rechteck auf der linken Seite dargestellt. Er sendet eine Anforderung und erhält eine Antwort von der Anwendung, die in einem Rechteck auf der rechten Seite dargestellt ist. Innerhalb des Anwendungsrechtecks stellen drei Rechtecke den Controller, das Modell und die Datenzugriffsschicht dar. Die Anforderung kommt im Controller der Anwendung an, und Lese-/Schreibvorgänge finden zwischen dem Controller und der Datenzugriffsschicht statt. Das Modell wird serialisiert und in der Antwort an den Client zurückgegeben.

Voraussetzungen

Erstellen eines Webprojekts

  • Klicken Sie im Menü Datei auf Neu>Projekt.
  • Geben Sie Web-API in das Suchfeld ein.
  • Wählen Sie die ASP.NET Core-Web-API-Vorlage aus, und klicken Sie auf Weiter.
  • Geben Sie im Dialogfeld Neues Projekt konfigurieren dem Projekt den Namen TodoApi, und wählen Sie dann Weiter aus.
  • Im Dialogfeld Zusätzliche Informationen:
    • Bestätigen Sie, dass das Framework auf .NET 8.0 (Langfristiger Support) festgelegt ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen Controller verwenden (zur Verwendung minimaler APIs deaktivieren) aktiviert ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen OpenAPI-Unterstützung aktivieren aktiviert ist.
    • Klicken Sie auf Erstellen.

Hinzufügen eines NuGet-Pakets

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

  • Klicken Sie im Menü Extras auf NuGet-Paket-Manager > NuGet-Pakete für Projektmappe verwalten.
  • Wählen Sie die Registerkarte Durchsuchen aus.
  • Geben Sie Microsoft.EntityFrameworkCore.InMemory in das Suchfeld ein, und wählen Sie Microsoft.EntityFrameworkCore.InMemory aus.
  • Aktivieren Sie das Kontrollkästchen Projekt im rechten Bereich, und klicken Sie dann auf Installieren.

Hinweis

Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.

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 SSL-Zertifikat von IIS Express vertrauen?

Wählen Sie Ja aus, wenn Sie dem IIS Express-SLL-Zertifikat vertrauen möchten.

Das folgende Dialogfeld wird angezeigt:

Dialogfeld „Sicherheitswarnung“

Klicken Sie auf Ja, wenn Sie zustimmen möchten, dass das Entwicklungszertifikat vertrauenswürdig ist.

Informationen dazu, wie Sie dem Firefox-Browser vertrauen, finden Sie unter Firefox-Zertifikatfehler SEC_ERROR_INADEQUATE_KEY_USAGE.

Visual Studio startet einen Standardbrowser und navigiert zu https://localhost:<port>/swagger/index.html, wobei es sich bei <port> um eine zufällig ausgewählte Portnummer handelt.

Die Swagger-Seite /swagger/index.html wird angezeigt. Wählen Sie GET>Tryit out>Execute (GET > Testen> Ausführen) aus. Die Seite zeigt Folgendes an:

  • Der Curl-Befehl, zum Testen der WeatherForecast-API.
  • 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 Swagger-Seite nicht angezeigt wird, finden Sie weitere Informationen in diesem GitHub-Issue.

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 im 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 Gruppe von Klassen, die die Daten darstellen, die die App verwaltet. Das Modell für diese App ist die Klasse TodoItem.

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt. Klicken Sie auf Hinzufügen>Neuer Ordner. Geben Sie dem Ordner den Namen Modelsanmelden.
  • Klicken Sie mit der rechten Maustaste auf den Ordner Models, und wählen Sie Hinzufügen>Klasse aus. Nennen 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-Funktionen 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 Ordner Models, und wählen Sie Hinzufügen>Klasse aus. Nennen 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 mit dem Container Abhängigkeitsinjektion 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 Abhängigkeitscontainer 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.

  • Klicken Sie auf API-Controller mit Aktionen unter Verwendung von Entity Framework und dann auf Hinzufügen.

  • Führen Sie im Dialogfeld API-Controller mit Aktionen unter Verwendung von Entity Framework folgende Schritte aus:

    • Wählen Sie in der Modellklasse das Element TodoItem (TodoApi.Models) aus.
    • Wählen Sie in der Datenkontextklasse das Element TodoContext (TodoApi.Models) aus.
    • Wählen Sie Hinzufügen aus.

    Wenn beim Gerüstbauvorgang ein Fehler auftritt, wählen Sie Hinzufügen aus, um ein zweites Mal den Gerüstbau zu versuchen.

Der generierte Code hat folgende Auswirkungen:

  • Markiert die Klasse mit dem [ApiController]-Attribut. Dieses Attribut gibt an, dass der Controller auf Web-API-Anforderungen reagiert. Informationen über bestimmte Verhaltensweisen, die das Attribut aktivieren, finden Sie unter Erstellen von Web-APIs mit ASP.NET Core.
  • Verwendet die Abhängigkeitsinjektion, um den Datenbankkontext (TodoContext) dem Controller hinzuzufügen. Der Datenbankkontext wird in den einzelnen CRUD-Methoden im Controller 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 sich das [action]-Token nicht in der Routenvorlage befindet, 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 mit dem nameof-Operator:

[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 Erfolg den HTTP-Statuscode 201 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. Der Location-Header legt den URI des neu erstellten To-do-Elements fest. Weitere Informationen finden Sie unter 10.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 Try it out aus.

  • Aktualisieren Sie im Eingabefenster Anforderungstext das JSON. Beispiel:

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Wählen Sie Execute.

    Swagger POST

Testen des Adressheader-URIs

In der vorstehenden POST zeigt die Swagger-Benutzeroberfläche den Adressheader unter Response Headers an. Beispiel: location: https://localhost:7260/api/TodoItems/1. Der Adressheader zeigt den URI für die erstellte Ressource an.

Testen des Adressheaders:

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

  • Geben Sie 1 in das Eingabefeld id ein, und wählen Sie dann Execute 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 mit 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. In diesem Beispiel ist der Klassenname des Controllers „TodoItemsController“. Der Controllername lautet also „TodoItems“. Beim ASP.NET Core-Routing wird die Groß-/Kleinschreibung nicht beachtet.

  • 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 Wert von "{id}" in der URL der Methode in ihrem Parameter id 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 Methoden GetTodoItems und GetTodoItem ist ActionResult<T>-Typ . ASP.NET Core serialisiert automatisch das Objekt in JSON und schreibt den JSON-Code in den Text der Antwortnachricht. Der Antwortcode für diesen Rückgabetyp ist 200 OK, vorausgesetzt, es gibt keine Ausnahmefehler. 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 einen NotFound-Fehlercode Status 404 zurück.
  • 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 ist 204 (No Content). 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.

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. In diesem Tutorial wird DTO verwendet.

Ein DTO kann für Folgendes verwendet werden:

  • Vermeiden Sie Overposting.
  • Ausblenden von Eigenschaften, die Clients nicht anzeigen 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

Mehr dazu finden Sie im -Tutorial: Aufrufen einer ASP.NET Core-Web-API mit JavaScript.

Videoreihe zur Web-API

Sehen Sie sich das Video: Einsteigerreihe: Web-APIs an.

Zuverlässige Web-App-Muster

Einen Leitfaden zum Erstellen einer modernen, zuverlässigen, leistungsfähigen, testbaren, kosteneffizienten und skalierbaren ASP.NET Core-App finden Sie in den YouTube-Videos und im Artikel zum zuverlässigen Web-App-Muster für .NET – ganz gleich, ob Sie eine App von Grund auf neu erstellen oder umgestalten möchten.

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
  • Federation Gateway

Wichtig

Duende Software erhebt ggf. eine Lizenzgebühr für die Nutzung von Duende Identity Server in der Produktion. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core 5.0 zu 6.0.

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

Veröffentlichen in Azure

Weitere Informationen zur Bereistellung in Azure finden Sie unter Schnellstart: Bereitstellen einer ASP.NET-Web-App.

Zusätzliche Ressourcen

Sie können den Beispielcode für dieses Tutorial anzeigen oder herunterladen. Informationen zum Herunterladen finden Sie hier.

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 anderer Ansatz zum Erstellen von APIs in ASP.NET Core besteht in der Erstellung von minimalen APIs. Hilfe bei der Entscheidung zwischen minimalen APIs und controllerbasierten APIs finden Sie in der Übersicht über APIs. Anleitungen zum Erstellen einer minimalen API finden Sie im Tutorial: Erstellen einer minimalen API mit ASP.NET Core.

Übersicht

In diesem Tutorial wird die folgende API erstellt:

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 To-do-Element
POST /api/todoitems Neues Element hinzufügen To-do-Element To-do-Element
PUT /api/todoitems/{id} Vorhandenes Element aktualisieren To-do-Element Keine
DELETE /api/todoitems/{id}     Löschen eines Elements Keine Keine

Das folgende Diagramm zeigt den Entwurf der App.

Der Client wird durch ein Rechteck auf der linken Seite dargestellt. Er sendet eine Anforderung und erhält eine Antwort von der Anwendung, die in einem Rechteck auf der rechten Seite dargestellt ist. Innerhalb des Anwendungsrechtecks stellen drei Rechtecke den Controller, das Modell und die Datenzugriffsschicht dar. Die Anforderung kommt im Controller der Anwendung an, und Lese-/Schreibvorgänge finden zwischen dem Controller und der Datenzugriffsschicht statt. Das Modell wird serialisiert und in der Antwort an den Client zurückgegeben.

Voraussetzungen

Erstellen eines Webprojekts

  • Klicken Sie im Menü Datei auf Neu>Projekt.
  • Geben Sie Web-API in das Suchfeld ein.
  • Wählen Sie die ASP.NET Core-Web-API-Vorlage aus, und klicken Sie auf Weiter.
  • Geben Sie im Dialogfeld Neues Projekt konfigurieren dem Projekt den Namen TodoApi, und wählen Sie dann Weiter aus.
  • Im Dialogfeld Zusätzliche Informationen:
    • Bestätigen Sie, dass das Framework auf .NET 8.0 (Langfristiger Support) festgelegt ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen Controller verwenden (zur Verwendung minimaler APIs deaktivieren) aktiviert ist.
    • Vergewissern Sie sich, dass das Kontrollkästchen OpenAPI-Unterstützung aktivieren aktiviert ist.
    • Klicken Sie auf Erstellen.

Hinzufügen eines NuGet-Pakets

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

  • Klicken Sie im Menü Extras auf NuGet-Paket-Manager > NuGet-Pakete für Projektmappe verwalten.
  • Wählen Sie die Registerkarte Durchsuchen aus.
  • Geben Sie Microsoft.EntityFrameworkCore.InMemory in das Suchfeld ein, und wählen Sie Microsoft.EntityFrameworkCore.InMemory aus.
  • Aktivieren Sie das Kontrollkästchen Projekt im rechten Bereich, und klicken Sie dann auf Installieren.

Hinweis

Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.

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 SSL-Zertifikat von IIS Express vertrauen?

Wählen Sie Ja aus, wenn Sie dem IIS Express-SLL-Zertifikat vertrauen möchten.

Das folgende Dialogfeld wird angezeigt:

Dialogfeld „Sicherheitswarnung“

Klicken Sie auf Ja, wenn Sie zustimmen möchten, dass das Entwicklungszertifikat vertrauenswürdig ist.

Informationen dazu, wie Sie dem Firefox-Browser vertrauen, finden Sie unter Firefox-Zertifikatfehler SEC_ERROR_INADEQUATE_KEY_USAGE.

Visual Studio startet einen Standardbrowser und navigiert zu https://localhost:<port>/swagger/index.html, wobei es sich bei <port> um eine zufällig ausgewählte Portnummer handelt.

Die Swagger-Seite /swagger/index.html wird angezeigt. Wählen Sie GET>Tryit out>Execute (GET > Testen> Ausführen) aus. Die Seite zeigt Folgendes an:

  • Der Curl-Befehl, zum Testen der WeatherForecast-API.
  • 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 Swagger-Seite nicht angezeigt wird, finden Sie weitere Informationen in diesem GitHub-Issue.

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 im 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 Gruppe von Klassen, die die Daten darstellen, die die App verwaltet. Das Modell für diese App ist die Klasse TodoItem.

  • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt. Klicken Sie auf Hinzufügen>Neuer Ordner. Geben Sie dem Ordner den Namen Modelsanmelden.
  • Klicken Sie mit der rechten Maustaste auf den Ordner Models, und wählen Sie Hinzufügen>Klasse aus. Nennen 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-Funktionen 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 Ordner Models, und wählen Sie Hinzufügen>Klasse aus. Nennen 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 mit dem Container Abhängigkeitsinjektion 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 Abhängigkeitscontainer 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.

  • Klicken Sie auf API-Controller mit Aktionen unter Verwendung von Entity Framework und dann auf Hinzufügen.

  • Führen Sie im Dialogfeld API-Controller mit Aktionen unter Verwendung von Entity Framework folgende Schritte aus:

    • Wählen Sie in der Modellklasse das Element TodoItem (TodoApi.Models) aus.
    • Wählen Sie in der Datenkontextklasse das Element TodoContext (TodoApi.Models) aus.
    • Wählen Sie Hinzufügen aus.

    Wenn beim Gerüstbauvorgang ein Fehler auftritt, wählen Sie Hinzufügen aus, um ein zweites Mal den Gerüstbau zu versuchen.

Der generierte Code hat folgende Auswirkungen:

  • Markiert die Klasse mit dem [ApiController]-Attribut. Dieses Attribut gibt an, dass der Controller auf Web-API-Anforderungen reagiert. Informationen über bestimmte Verhaltensweisen, die das Attribut aktivieren, finden Sie unter Erstellen von Web-APIs mit ASP.NET Core.
  • Verwendet die Abhängigkeitsinjektion, um den Datenbankkontext (TodoContext) dem Controller hinzuzufügen. Der Datenbankkontext wird in den einzelnen CRUD-Methoden im Controller 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 sich das [action]-Token nicht in der Routenvorlage befindet, 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 mit dem nameof-Operator:

[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 Erfolg den HTTP-Statuscode 201 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. Der Location-Header legt den URI des neu erstellten To-do-Elements fest. Weitere Informationen finden Sie unter 10.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 Try it out aus.

  • Aktualisieren Sie im Eingabefenster Anforderungstext das JSON. Beispiel:

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Wählen Sie Execute.

    Swagger POST

Testen des Adressheader-URIs

In der vorstehenden POST zeigt die Swagger-Benutzeroberfläche den Adressheader unter Response Headers an. Beispiel: location: https://localhost:7260/api/TodoItems/1. Der Adressheader zeigt den URI für die erstellte Ressource an.

Testen des Adressheaders:

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

  • Geben Sie 1 in das Eingabefeld id ein, und wählen Sie dann Execute 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 mit 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. In diesem Beispiel ist der Klassenname des Controllers „TodoItemsController“. Der Controllername lautet also „TodoItems“. Beim ASP.NET Core-Routing wird die Groß-/Kleinschreibung nicht beachtet.

  • 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 Wert von "{id}" in der URL der Methode in ihrem Parameter id 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 Methoden GetTodoItems und GetTodoItem ist ActionResult<T>-Typ . ASP.NET Core serialisiert automatisch das Objekt in JSON und schreibt den JSON-Code in den Text der Antwortnachricht. Der Antwortcode für diesen Rückgabetyp ist 200 OK, vorausgesetzt, es gibt keine Ausnahmefehler. 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 einen NotFound-Fehlercode Status 404 zurück.
  • 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 ist 204 (No Content). 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.

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. In diesem Tutorial wird DTO verwendet.

Ein DTO kann für Folgendes verwendet werden:

  • Vermeiden Sie Overposting.
  • Ausblenden von Eigenschaften, die Clients nicht anzeigen 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

Mehr dazu finden Sie im -Tutorial: Aufrufen einer ASP.NET Core-Web-API mit JavaScript.

Videoreihe zur Web-API

Sehen Sie sich das Video: Einsteigerreihe: Web-APIs an.

Zuverlässige Web-App-Muster

Einen Leitfaden zum Erstellen einer modernen, zuverlässigen, leistungsfähigen, testbaren, kosteneffizienten und skalierbaren ASP.NET Core-App finden Sie in den YouTube-Videos und im Artikel zum zuverlässigen Web-App-Muster für .NET – ganz gleich, ob Sie eine App von Grund auf neu erstellen oder umgestalten möchten.

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
  • Federation Gateway

Wichtig

Duende Software erhebt ggf. eine Lizenzgebühr für die Nutzung von Duende Identity Server in der Produktion. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core 5.0 zu 6.0.

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

Veröffentlichen in Azure

Weitere Informationen zur Bereistellung in Azure finden Sie unter Schnellstart: Bereitstellen einer ASP.NET-Web-App.

Zusätzliche Ressourcen

Sie können den Beispielcode für dieses Tutorial anzeigen oder herunterladen. Informationen zum Herunterladen finden Sie hier.

Weitere Informationen finden Sie in den folgenden Ressourcen: