Tutorial: Erstellen einer Minimal-Web-API mit ASP.NET Core

Von Rick Anderson

Minimal-APIs sind so entworfen, dass HTTP-APIs mit minimalen Abhängigkeiten erstellt werden. Sie eignen sich ideal für Microservices und Apps, die nur ein Minimum an Dateien, Funktionen und Abhängigkeiten in ASP.NET Core enthalten sollen.

In diesem Tutorial lernen Sie die Grundlagen der Erstellung einer minimalen Web-API mit ASP.NET Core kennen. Ein Tutorial zum Erstellen eines Web-API-Projekts basierend auf Controllern, die weitere Features umfassen, finden Sie unter Erstellen einer Web-API.

Übersicht

In diesem Tutorial wird die folgende API erstellt:

API Beschreibung Anforderungstext Antworttext
GET / Browsertest, „Hello World“ Keine Hello World!
GET /todoitems Alle To-do-Elemente abrufen Keine Array von To-do-Elementen
GET /todoitems/complete Abgeschlossene To-Do-Elemente Keine Array von To-do-Elementen
GET /todoitems/{id} Ein Element nach ID abrufen Keine To-do-Element
POST /todoitems Neues Element hinzufügen To-do-Element To-do-Element
PUT /todoitems/{id} Vorhandenes Element aktualisieren To-do-Element Keine
DELETE /todoitems/{id}     Löschen eines Elements Keine Keine

Voraussetzungen

VS22 installer workloads

Erstellen eines Web-API-Projekts

  • Starten Sie Visual Studio 2022, und wählen Sie Neues Projekt erstellen aus.

  • Im Dialogfeld Neues Projekt erstellen:

    • Geben Sie im Suchfeld APINach Vorlagen suchenden Suchbegriff ein.
    • Wählen Sie die ASP.NET Core-Web-API-Vorlage aus, und klicken Sie auf Weiter. Visual Studio Create a new project
  • Geben Sie dem Projekt den Namen TodoApi, und klicken Sie auf Weiter.

  • Im Dialogfeld Zusätzliche Informationen:

    • Wählen Sie .NET 6.0 (Langfristiger Support) aus.
    • Deaktivieren Sie Controller verwenden (zur Verwendung von Minimal-APIs deaktivieren)
    • Klicken Sie auf Erstellen

Additional information

Untersuchen des Codes

Die Datei Program.cs enthält den folgenden Code:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
       new WeatherForecast
       (
           DateTime.Now.AddDays(index),
           Random.Shared.Next(-20, 55),
           summaries[Random.Shared.Next(summaries.Length)]
       ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast");

app.Run();

internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Die Projektvorlage erstellt eine WeatherForecast-API mit Unterstützung für Swagger. Swagger wird verwendet, um hilfreiche Dokumentation und Hilfeseiten für Web-APIs zu generieren.

Der folgende hervorgehobene Code fügt Unterstützung für Swagger hinzu:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

Ausführen der App

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

In Visual Studio wird das folgende Dialogfeld angezeigt:

This project is configured to use SSL. To avoid SSL warnings in the browser you can choose to trust the self-signed certificate that IIS Express has generated. Would you like to trust the IIS Express SSL certificate?

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

Das folgende Dialogfeld wird angezeigt:

Security warning dialog

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 den Kestrel-Webserver.

Die Swagger-Seite /swagger/index.html wird angezeigt. Wählen Sie GET > Try it out> Executeaus. 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.

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 folgt aus:

[
  {
    "date": "2021-10-19T14:12:50.3079024-10:00",
    "temperatureC": 13,
    "summary": "Bracing",
    "temperatureF": 55
  },
  {
    "date": "2021-10-20T14:12:50.3080559-10:00",
    "temperatureC": -8,
    "summary": "Bracing",
    "temperatureF": 18
  },
  {
    "date": "2021-10-21T14:12:50.3080601-10:00",
    "temperatureC": 12,
    "summary": "Hot",
    "temperatureF": 53
  },
  {
    "date": "2021-10-22T14:12:50.3080603-10:00",
    "temperatureC": 10,
    "summary": "Sweltering",
    "temperatureF": 49
  },
  {
    "date": "2021-10-23T14:12:50.3080604-10:00",
    "temperatureC": 36,
    "summary": "Warm",
    "temperatureF": 96
  }
]

Aktualisieren des generierten Codes

Dieses Tutorial konzentriert sich auf die Erstellung einer Web-API, deshalb löschen wir den Swagger-Code und den WeatherForecast-Code. Ersetzen Sie den Inhalt der Datei Program.cs durch Folgendes:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Mit dem folgenden hervorgehobenen Code werden ein WebApplicationBuilder und eine WebApplication mit vorkonfigurierten Standardwerten erstellt:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Der nachstehende Code erstellt einen HTTP GET-Endpunkt /, der Hello World! zurückgibt:

app.MapGet("/", () => "Hello World!");

app.Run(); führt die App aus.

Entfernen Sie die beiden "launchUrl": "swagger",-Zeilen aus der Properties/launchSettings.json-Datei. Wenn die launchUrl nicht angegeben ist, fordert der Webbrowser den Endpunkt / an.

Führen Sie die App aus. Hello World! wird angezeigt. Die aktualisierte Datei Program.cs enthält eine minimale, aber vollständige App.

Hinzufügen von NuGet-Paketen

NuGet-Pakete müssen hinzugefügt werden, um die in diesem Tutorial verwendete Datenbank und Diagnose zu unterstützen.

  • Klicken Sie im Menü Extras auf NuGet-Paket-Manager > NuGet-Pakete für Projektmappe verwalten.
  • 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.
  • Folgen Sie den vorstehenden Anweisungen, um das Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore-Paket hinzuzufügen.

Hinzufügen des API-Codes

Ersetzen Sie den Inhalt der Datei Program.cs durch den folgenden Code:

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.MapGet("/todoitems", async (TodoDb db) =>
    await db.Todos.ToListAsync());

app.MapGet("/todoitems/complete", async (TodoDb db) =>
    await db.Todos.Where(t => t.IsComplete).ToListAsync());

app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
    await db.Todos.FindAsync(id)
        is Todo todo
            ? Results.Ok(todo)
            : Results.NotFound());

app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todo.Id}", todo);
});

app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
    var todo = await db.Todos.FindAsync(id);

    if (todo is null) return Results.NotFound();

    todo.Name = inputTodo.Name;
    todo.IsComplete = inputTodo.IsComplete;

    await db.SaveChangesAsync();

    return Results.NoContent();
});

app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
    if (await db.Todos.FindAsync(id) is Todo todo)
    {
        db.Todos.Remove(todo);
        await db.SaveChangesAsync();
        return Results.Ok(todo);
    }

    return Results.NotFound();
});

app.Run();

class Todo
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

class TodoDb : DbContext
{
    public TodoDb(DbContextOptions<TodoDb> options)
        : base(options) { }

    public DbSet<Todo> Todos => Set<Todo>();
}

Die Modell- und Datenbankkontextklassen

Die Beispiel-App enthält das folgende Modell:

class Todo
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Ein Modell ist eine Klasse, welche die in der App verwalteten Daten repräsentiert. Das Modell für diese App ist die Klasse Todo.

Die Beispiel-App enthält außerdem die folgende Datenbankkontextklasse:

class TodoDb : DbContext
{
    public TodoDb(DbContextOptions<TodoDb> options)
        : base(options) { }

    public DbSet<Todo> Todos => Set<Todo>();
}

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.

Der folgende hervorgehobene Code fügt den Datenbankkontext zum Container für die Abhängigkeitsinjektion (Dependency Injection, DI) hinzu und ermöglicht die Anzeige von datenbankbezogenen Ausnahmen:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();

Der DI-Container bietet Zugriff auf den Datenbankkontext und andere Dienste.

Der folgende Code erstellt einen HTTP POST-Endpunkt /todoitems zum Hinzufügen von Daten zur In-Memory-Datenbank:

app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todo.Id}", todo);
});

Installieren von Postman zum Testen der App

Dieses Tutorial verwendet Postman zum Testen der API.

  • Installieren Sie Postman.
  • Starten Sie die Web-App.
  • Starten Sie Postman.
  • Deaktivieren Sie SSL certificate verification (Verifizierung des SSL-Zertifikats).
    • Deaktivieren Sie auf der Registerkarte General (Allgemein) unter File>Settings (Datei > Einstellungen) SSL certificate verification (Verifizierung des SSL-Zertifikats).

      Warnung

      Aktivieren Sie die Verifizierung des SSL-Zertifikats wieder, nachdem Sie den Controller getestet haben.

Testen der Übertragung von Daten

Befolgen Sie diese Anweisungen, um Daten an die App zu übertragen:

  • Erstellen Sie eine neue Anforderung.

  • Legen Sie als HTTP-Methode POST fest.

  • Legen Sie den URI auf https://localhost:<port>/todoitems fest. Beispiel: https://localhost:5001/todoitems

  • Wählen Sie die Registerkarte Body (Text) aus.

  • Wählen Sie raw (Unformatiert) aus.

  • Legen Sie den Typ auf JSON fest.

  • Geben Sie für die Aufgabe den Anforderungstext im JSON-Format ein:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • Wählen Sie Send (Senden) aus. Postman with Post request details

Untersuchen der GET-Endpunkte

Die Beispiel-App implementiert mehrere GET-Endpunkte mithilfe von MapGet-Aufrufen:

API Beschreibung Anforderungstext Antworttext
GET / Browsertest, „Hello World“ Keine Hello World!
GET /todoitems Alle To-do-Elemente abrufen Keine Array von To-do-Elementen
GET /todoitems/complete Alle abgeschlossenen To-do-Elemente abrufen Keine Array von To-do-Elementen
GET /todoitems/{id} Ein Element nach ID abrufen Keine To-do-Element
app.MapGet("/", () => "Hello World!");

app.MapGet("/todoitems", async (TodoDb db) =>
    await db.Todos.ToListAsync());

app.MapGet("/todoitems/complete", async (TodoDb db) =>
    await db.Todos.Where(t => t.IsComplete).ToListAsync());

app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
    await db.Todos.FindAsync(id)
        is Todo todo
            ? Results.Ok(todo)
            : Results.NotFound());

Testen der GET-Endpunkte

Testen Sie die App, indem Sie die beiden Endpunkte in einem Browser oder über Postman aufrufen. Zum Beispiel:

  • GET https://localhost:5001/todoitems
  • GET https://localhost:5001/todoitems/1

Durch einen Aufruf von GET /todoitems wird eine Antwort ähnlich der folgenden erzeugt:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

Testen der GET-Endpunkte mit Postman

  • Erstellen Sie eine neue Anforderung.
  • Legen Sie die HTTP-Methode auf GET fest.
  • Legen Sie den Anforderungs-URI auf https://localhost:<port>/todoitems fest. Beispiel: https://localhost:5001/todoitems.
  • Wählen Sie Send (Senden) aus.

Diese App verwendet eine In-Memory-Datenbank. Wenn die App neu gestartet wird, gibt die GET-Anforderung keinerlei Daten zurück. Wenn keine Daten zurückgegeben werden, senden Sie mit POST Daten an die App.

Rückgabewerte

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.

Die Rückgabetypen können eine Vielzahl von HTTP-Statuscodes darstellen. Beispielsweise kann GET /todoitems/{id} 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.

Untersuchen des PUT-Endpunkts

Die Beispiel-App implementiert einen einzelnen PUT-Endpunkt mithilfe von MapPut:

app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
    var todo = await db.Todos.FindAsync(id);

    if (todo is null) return Results.NotFound();

    todo.Name = inputTodo.Name;
    todo.IsComplete = inputTodo.IsComplete;

    await db.SaveChangesAsync();

    return Results.NoContent();
});

Diese Methode ähnelt der MapPost-Methode, verwendet jedoch HTTP PUT. Eine erfolgreiche Antwort gibt 204 (No Content) zurück. 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 des PUT-Endpunkts

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.

Aktualisieren Sie das To-do-Element, das über den ID-Wert 1 verfügt, und legen Sie als Namen "feed fish" fest:

{
  "id": 1,
  "name": "feed fish",
  "isComplete": false
}

Untersuchen des DELETE-Endpunkts

Die Beispiel-App implementiert einen einzelnen DELETE-Endpunkt mithilfe von MapDelete:

app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
    if (await db.Todos.FindAsync(id) is Todo todo)
    {
        db.Todos.Remove(todo);
        await db.SaveChangesAsync();
        return Results.Ok(todo);
    }

    return Results.NotFound();
});

So löschen Sie mit Postman eine Aufgabe

  • Legen Sie die Methode auf DELETE fest.
  • Legen Sie den URI des zu löschenden Objekts fest, z. B. https://localhost:5001/todoitems/1.
  • Wählen Sie Send (Senden) aus.

Vermeiden von Overposting

Derzeit macht die Beispiel-App das gesamte Todo-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 Artikel wird das 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 Todo-Klasse, sodass sie ein geheimes Feld einschließt:

public class Todo
{
    public int 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:

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

    public TodoItemDTO() { }
    public TodoItemDTO(Todo todoItem) =>
    (Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}

Aktualisieren Sie den Code, um TodoItemDTO zu verwenden:

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();

app.MapGet("/todoitems", async (TodoDb db) =>
    await db.Todos.Select(x => new TodoItemDTO(x)).ToListAsync());

app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
    await db.Todos.FindAsync(id)
        is Todo todo
            ? Results.Ok(new TodoItemDTO(todo))
            : Results.NotFound());

app.MapPost("/todoitems", async (TodoItemDTO todoItemDTO, TodoDb db) =>
{
    var todoItem = new Todo
    {
        IsComplete = todoItemDTO.IsComplete,
        Name = todoItemDTO.Name
    };

    db.Todos.Add(todoItem);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todoItem.Id}", new TodoItemDTO(todoItem));
});

app.MapPut("/todoitems/{id}", async (int id, TodoItemDTO todoItemDTO, TodoDb db) =>
{
    var todo = await db.Todos.FindAsync(id);

    if (todo is null) return Results.NotFound();

    todo.Name = todoItemDTO.Name;
    todo.IsComplete = todoItemDTO.IsComplete;

    await db.SaveChangesAsync();

    return Results.NoContent();
});

app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
    if (await db.Todos.FindAsync(id) is Todo todo)
    {
        db.Todos.Remove(todo);
        await db.SaveChangesAsync();
        return Results.Ok(new TodoItemDTO(todo));
    }

    return Results.NotFound();
});

app.Run();

public class Todo
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
    public string? Secret { get; set; }
}

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

    public TodoItemDTO() { }
    public TodoItemDTO(Todo todoItem) =>
    (Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}


class TodoDb : DbContext
{
    public TodoDb(DbContextOptions<TodoDb> options)
        : base(options) { }

    public DbSet<Todo> Todos => Set<Todo>();
}

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

Unterschiede zwischen Minimal-APIs und APIs mit Controllern

Verwenden von JsonOptions

Der folgende Code verwendet JsonOptions:

using Microsoft.AspNetCore.Http.Json;

var builder = WebApplication.CreateBuilder(args);

// Configure JSON options
builder.Services.Configure<JsonOptions>(options =>
{
    options.SerializerOptions.IncludeFields = true;
});

var app = builder.Build();

app.MapGet("/", () => new Todo { Name = "Walk dog", IsComplete = false });

app.Run();

class Todo
{
    // These are public fields instead of properties.
    public string? Name;
    public bool IsComplete;
}

Der folgende Code verwendet JsonSerializerOptions:

using System.Text.Json;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);

app.MapGet("/", () => Results.Json(new Todo {
                      Name = "Walk dog", IsComplete = false }, options));

app.Run();

class Todo
{
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Im vorangehenden Code werden Webstandardwerte verwendet, mit denen Eigenschaftsnamen in das Camel Case-Format konvertiert werden.

Testen der Minimal-API

Ein Beispiel für das Testen einer Minimal-API-App finden Sie in diesem GitHub-Beispiel.

Veröffentlichen in Azure

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

Zusätzliche Ressourcen