Freigeben über


Arbeiten mit OpenAPI-Dokumenten

Das Paket Microsoft.AspNetCore.OpenApi bietet integrierte Unterstützung für die OpenAPI-Dokumentgenerierung in ASP.NET Core. Das Paket bietet folgende Funktionen:

  • Unterstützung für das Generieren von OpenAPI-Dokumenten zur Laufzeit und Zugriff darauf über einen Endpunkt in der Anwendung
  • Unterstützung für „Transformator“-APIs, die das Ändern des generierten Dokuments ermöglichen
  • Unterstützung für das Generieren mehrerer OpenAPI-Dokumente aus einer einzelnen App
  • nutzt JSON-Schemaunterstützung, die von System.Text.Json bereitgestellt wird.
  • ist mit nativem AOT kompatibel.

Paketinstallation

Installieren Sie das Paket Microsoft.AspNetCore.OpenApi:

Führen Sie den folgenden Befehl in der Paket-Manager-Konsole aus:

Install-Package Microsoft.AspNetCore.OpenApi -IncludePrerelease

Um Unterstützung für das Generieren von OpenAPI-Dokumenten zum Zeitpunkt der Erstellung hinzuzufügen, installieren Sie das Microsoft.Extensions.ApiDescription.Server-Paket:

Führen Sie den folgenden Befehl in der Paket-Manager-Konsole aus:

Install-Package Microsoft.Extensions.ApiDescription.Server -IncludePrerelease

Konfigurieren der OpenAPI-Dokumentgenerierung

Der folgende Code führt folgende Aktionen aus:

  • Fügt OpenAPI-Dienste hinzu.
  • Aktiviert den Endpunkt zum Anzeigen des OpenAPI-Dokuments im JSON-Format.
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

Starten Sie die App, und navigieren Sie zu https://localhost:<port>/openapi/v1.json, um das generierte OpenAPI-Dokument anzuzeigen.

Einschließen von OpenAPI-Metadaten in eine ASP.NET-Web-App

ASP.NET sammelt Metadaten von den Endpunkten der Web-App und verwendet sie zum Generieren eines OpenAPI-Dokuments. In controllerbasierten Apps werden Metadaten aus Attributen wie [EndpointDescription], [HttpPost] und [Produces] gesammelt. In minimalen APIs können Metadaten aus Attributen gesammelt werden, sie können aber auch mithilfe von Erweiterungsmethoden und anderen Strategien festgelegt werden, z. B. das Zurückgeben von TypedResults von Routenhandlern. Die folgende Tabelle enthält eine Übersicht über die gesammelten Metadaten und die Strategien zum Festlegen der Metadaten.

Metadaten Attribut Erweiterungsmethode Weitere Strategien
Zusammenfassung [EndpointSummary] WithSummary
Beschreibung [EndpointDescription] WithDescription
Tags [Tags] WithTags
operationId [EndpointName] WithName
Parameter [FromQuery], [FromRoute], [FromHeader], [FromForm]
Parameterbeschreibung [Description]
requestBody [FromBody] Accepts
Antworten [Produces], [ProducesProblem] Produces, ProducesProblem TypedResults
Ausschließen von Endpunkten [ExcludeFromDescription] ExcludeFromDescription

ASP.NET Core sammelt keine Metadaten aus XML-Dokumentkommentaren.

In den folgenden Abschnitten wird veranschaulicht, wie Sie Metadaten in eine App integrieren, um das generierte OpenAPI-Dokument anzupassen.

Zusammenfassung und Beschreibung

Die Endpunktzusammenfassung und -beschreibung kann mit den [EndpointSummary]- und [EndpointDescription]-Attributen oder in minimalen APIs mit den WithSummary- und WithDescription-Erweiterungsmethoden festgelegt werden.

Im folgenden Beispiel werden die verschiedenen Strategien zum Festlegen von Zusammenfassungen und Beschreibungen veranschaulicht.

Beachten Sie, dass die Attribute in der Delegatmethode und nicht in der app.MapGet-Methode platziert werden.

app.MapGet("/extension-methods", () => "Hello world!")
  .WithSummary("This is a summary.")
  .WithDescription("This is a description.");

app.MapGet("/attributes",
  [EndpointSummary("This is a summary.")]
  [EndpointDescription("This is a description.")]
  () => "Hello world!");

Tags

OpenAPI unterstützt die Angabe von Tags auf jedem Endpunkt als Form der Kategorisierung. In controllerbasierten Apps wird der Controllername automatisch als Tag auf jedem seiner Endpunkte hinzugefügt; dies kann jedoch mithilfe des [Tags]-Attributs überschrieben werden. In minimalen APIs können Tags entweder mithilfe des [Tags]-Attributs oder der WithTags-Erweiterungsmethode festgelegt werden.

Im folgenden Beispiel werden die verschiedenen Strategien zum Festlegen von Tags veranschaulicht.

app.MapGet("/extension-methods", () => "Hello world!")
  .WithTags("todos", "projects");

app.MapGet("/attributes",
  [Tags("todos", "projects")]
  () => "Hello world!");

operationId

OpenAPI unterstützt eine operationId für jeden Endpunkt als eindeutigen Bezeichner oder Namen für den Vorgang. In controllerbasierten Apps kann die operationId mithilfe des [EndpointName]-Attributs festgelegt werden. In minimalen APIs kann die operationId entweder mithilfe des [EndpointName]-Attributs oder der WithName-Erweiterungsmethode festgelegt werden.

Im folgenden Beispiel werden die verschiedenen Strategien zum Festlegen der operationId veranschaulicht.

app.MapGet("/extension-methods", () => "Hello world!")
  .WithName("FromExtensionMethods");

app.MapGet("/attributes",
  [EndpointName("FromAttributes")]
  () => "Hello world!");

Parameter

OpenAPI unterstützt Anmerkungen zu Pfad, Abfragezeichenfolge, Header und cookie-Parametern, die von einer API genutzt werden.

Das Framework leitet die Typen der Anforderungsparameter automatisch aus der Signatur des Routenhandlers ab.

Das [Description]-Attribut kann verwendet werden, um eine Beschreibung für einen Parameter bereitzustellen.

Im folgenden Beispiel wird veranschaulicht, wie eine Beschreibung für einen Parameter festgelegt wird.

app.MapGet("/attributes",
  ([Description("This is a description.")] string name) => "Hello world!");

requestBody

Um den Typ der Eingaben zu definieren, die als Anforderungstext übermittelt werden, konfigurieren Sie die Eigenschaften mit der Accepts-Methode, um den Objekt- und Inhaltstyp zu definieren, die vom Anforderungshandler erwartet werden. Im nachstehenden Beispiel akzeptiert der Endpunkt ein Todo-Objekt im Anforderungstext mit dem erwarteten Inhaltstyp application/xml.

app.MapPost("/todos/{id}", (int id, Todo todo) => ...)
  .Accepts<Todo>("application/xml");

Zusätzlich zur Accepts-Erweiterungsmethode kann ein Parametertyp durch Implementierung der IEndpointParameterMetadataProvider-Schnittstelle seine eigene Anmerkung beschreiben. Beispielsweise fügt der folgende Todo-Typ eine Anmerkung hinzu, die einen Anforderungstext mit dem Inhaltstyp application/xml erfordert.

public class Todo : IEndpointParameterMetadataProvider
{
    public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
    {
        builder.Metadata.Add(new AcceptsMetadata(["application/xml", "text/xml"], typeof(XmlBody)));
    }
}

Falls keine explizite Anmerkung angegeben wird, versucht das Framework, den Standardanforderungstyp zu bestimmen, wenn es einen Anforderungstextparameter im Endpunkthandler gibt. Der Rückschluss verwendet die folgende Heuristik, um die Anmerkung zu generieren:

  • Anforderungstextparameter, die über das Attribut [FromForm] aus einem Formular gelesen werden, werden mit dem Inhaltstyp multipart/form-data beschrieben.
  • Alle anderen Anforderungstextparameter werden mit dem Inhaltstyp application/json beschrieben.
  • Der Anforderungstext wird als optional behandelt, wenn er Nullwerte zulässt oder die AllowEmpty-Eigenschaft für das FromBody-Attribut festgelegt ist.

Beschreiben von Antworttypen

OpenAPI unterstützt die Bereitstellung einer Beschreibung der von einer API zurückgegebenen Antworten. Minimal-APIs unterstützen drei Strategien zum Festlegen des Antworttyps eines Endpunkts:

Mit der Erweiterungsmethode Produces können einem Endpunkt Produces-Metadaten hinzugefügt werden. Wenn keine Parameter angegeben werden, füllt die Erweiterungsmethode die Metadaten für den Zieltyp mit dem Statuscode 200 und dem Inhaltstyp application/json auf.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
  .Produces<IList<Todo>>();

Die Verwendung von TypedResults in der Implementierung des Routenhandlers eines Endpunkts schließt automatisch die Metadaten des Antworttyps für den Endpunkt ein. Der nachstehende Code versieht beispielsweise den Endpunkt automatisch mit einer Antwort unter dem Statuscode 200 mit dem Inhaltstyp application/json.

app.MapGet("/todos", async (TodoDb db) =>
{
    var todos = await db.Todos.ToListAsync();
    return TypedResults.Ok(todos);
});

Festlegen von Antworten für ProblemDetails

Beim Festlegen des Antworttyps für Endpunkte, die eine ProblemDetails-Antwort zurückgeben können, kann die Erweiterungsmethode ProducesProblem oder ProducesValidationProblem oder TypedResults.Problem verwendet werden, um den entsprechenden Kommentar zu den Metadaten des Endpunkts hinzuzufügen.

Wenn es keine expliziten Anmerkungen gibt, die mittels einer dieser Strategien bereitgestellt werden, versucht das Framework, einen Standardantworttyp zu bestimmen, indem es die Signatur der Antwort untersucht. Diese Standardantwort wird unter dem Statuscode 200 in der OpenAPI-Definition eingetragen.

Mehrere Antworttypen

Wenn ein Endpunkt verschiedene Antworttypen in verschiedenen Szenarien zurückgeben kann, können Sie Metadaten auf folgende Weise bereitstellen:

  • Rufen Sie die Produces-Erweiterungsmethode mehrmals auf, wie im folgenden Beispiel gezeigt:

    app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
             await db.Todos.FindAsync(id) 
             is Todo todo
             ? Results.Ok(todo) 
             : Results.NotFound())
       .Produces<Todo>(StatusCodes.Status200OK)
       .Produces(StatusCodes.Status404NotFound);
    
  • Verwenden Sie Results<TResult1,TResult2,TResultN> in der Signatur und TypedResults im Textkörper des Handlers, wie im folgenden Beispiel gezeigt:

    app.MapGet("/book{id}", Results<Ok<Book>, NotFound> (int id, List<Book> bookList) =>
    {
        return bookList.FirstOrDefault((i) => i.Id == id) is Book book
         ? TypedResults.Ok(book)
         : TypedResults.NotFound();
    });
    

    Die Results<TResult1,TResult2,TResultN>-Uniontypen deklarieren, dass ein Routenhandler mehrere IResult implementierende konkrete Typen zurückgibt, und jeder dieser Typen, die IEndpointMetadataProvider implementieren, trägt zu den Metadaten des Endpunkts bei.

    Die Union-Typen implementieren implizite Umwandlungsoperatoren. Diese Operatoren ermöglichen dem Compiler, die in den generischen Argumenten angegebenen Typen automatisch in eine Instanz des Union-Typs zu konvertieren. Diese Fähigkeit hat den zusätzlichen Vorteil, dass zur Kompilierungszeit überprüft wird, ob ein Routenhandler nur die Ergebnisse zurückgibt, die er deklariert. Der Versuch, einen Typ zurückzugeben, der nicht als eines der generischen Argumente für Results<TResult1,TResult2,TResultN> deklariert wurde, führt zu einem Kompilierungsfehler.

Ausschließen von Endpunkten aus dem generierten Dokument

Standardmäßig werden alle Endpunkte, die in einer App definiert sind, in der generierten OpenAPI-Datei dokumentiert. Minimal-APIs unterstützen zwei Strategien zum Ausschließen eines bestimmten Endpunkts aus dem OpenAPI-Dokument, und zwar unter Verwendung von:

Im folgenden Beispiel werden die verschiedenen Strategien zum Ausschließen eines bestimmten Endpunkts aus dem generierten OpenAPI-Dokument veranschaulicht.

app.MapGet("/extension-method", () => "Hello world!")
  .ExcludeFromDescription();

app.MapGet("/attributes",
  [ExcludeFromDescription]
  () => "Hello world!");

Optionen zum Anpassen der OpenAPI-Dokumentgenerierung

In den folgenden Abschnitten wird veranschaulicht, wie Sie die OpenAPI-Dokumentgenerierung anpassen.

Anpassen des OpenAPI-Dokumentnamens

Jedes OpenAPI-Dokument in einer App hat einen eindeutigen Namen. Der registrierte Standarddokumentname ist v1.

builder.Services.AddOpenApi(); // Document name is v1

Der Dokumentname kann geändert werden, indem der Name als Parameter an den AddOpenApi-Aufruf übergeben wird.

builder.Services.AddOpenApi("internal"); // Document name is internal

Der Dokumentname wird an mehreren Stellen in der OpenAPI-Implementierung angezeigt.

Beim Abrufen des generierten OpenAPI-Dokuments wird der Dokumentname als documentName-Parameterargument in der Anforderung angegeben. Die folgenden Anforderungen lösen die Dokumente v1 und internal auf.

GET http://localhost:5000/openapi/v1.json
GET http://localhost:5000/openapi/internal.json

Anpassen der OpenAPI-Version eines generierten Dokuments

Standardmäßig generiert die OpenAPI-Dokumentgenerierung ein Dokument, das mit v3.0 der OpenAPI-Spezifikation kompatibel ist. Der folgende Code veranschaulicht, wie die Standardversion des OpenAPI-Dokuments geändert wird:

builder.Services.AddOpenApi(options =>
{
    options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0;
});

Anpassen der OpenAPI-Endpunktroute

Standardmäßig macht der über einen Aufruf von MapOpenApi registrierte OpenAPI-Endpunkt das Dokument am /openapi/{documentName}.json-Endpunkt verfügbar. Der folgende Code veranschaulicht, wie Sie die Route anpassen, mit der das OpenAPI-Dokument registriert ist:

app.MapOpenApi("/openapi/{documentName}/openapi.json");

Der documentName-Routenparameter kann aus der Endpunktroute entfernt werden, dies wird aber nicht empfohlen. Wenn der Routenparameter documentName aus der Endpunktroute entfernt wird, versucht das Framework, den Dokumentnamen aus dem Abfrageparameter aufzulösen. Wenn documentName weder in der Route noch in der Abfrage angegeben wird, kann das zu unerwartetem Verhalten führen.

Anpassen des OpenAPI-Endpunkts

Da das OpenAPI-Dokument über einen Routenhandler-Endpunkt bereitgestellt wird, stehen alle Anpassungen, die für standardmäßige minimale Endpunkte verfügbar sind, für den OpenAPI-Endpunkt zur Verfügung.

Einschränken des Zugriffs auf das OpenAPI-Dokument auf autorisierte Benutzer:innen

Der OpenAPI-Endpunkt aktiviert standardmäßig keine Autorisierungsüberprüfungen. Es ist jedoch möglich, den Zugriff auf das OpenAPI-Dokument einzuschränken. Mit dem folgenden Code wird der Zugriff auf das OpenAPI-Dokument beispielsweise auf Personen mit der Rolle tester beschränkt:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization(o =>
{
    o.AddPolicy("ApiTesterPolicy", b => b.RequireRole("tester"));
});
builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi()
    .RequireAuthorization("ApiTesterPolicy");

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

app.Run();

Zwischenspeichern des generierten OpenAPI-Dokuments

Das OpenAPI-Dokument wird jedes Mal erneut generiert, wenn eine Anforderung an den OpenAPI-Endpunkt gesendet wird. Durch die erneute Generierung können die Transformatoren dynamisch den Anwendungszustand in ihre Vorgänge integrieren. So können Sie z. B. eine Anforderung mit Details des HTTP-Kontexts neu generieren. Dementsprechend kann das OpenAPI-Dokument zwischengespeichert werden, um die Ausführung der Dokumentgenerierungspipeline für jede HTTP-Anforderung zu vermeiden.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(policy => policy.Expire(TimeSpan.FromMinutes(10)));
});
builder.Services.AddOpenApi();

var app = builder.Build();

app.UseOutputCache();

app.MapOpenApi()
    .CacheOutput();

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

app.Run();

Transformatoren für OpenAPI-Dokumente

In diesem Abschnitt wird veranschaulicht, wie OpenAPI-Dokumente mit Transformatoren angepasst werden.

Anpassen von OpenAPI-Dokumenten mit Transformatoren

Transformatoren bieten eine API zum Ändern des OpenAPI-Dokuments mit benutzerdefinierten Anpassungen. Transformatoren eignen sich z. B. für folgende Szenarien:

  • Hinzufügen von Parametern zu allen Vorgängen in einem Dokument
  • Ändern der Beschreibungen von Parametern oder Vorgängen
  • Hinzufügen von Informationen auf oberster Ebene zum OpenAPI-Dokument

Transformer sind in zwei Kategorien unterteilt:

  • Dokumenttransformatoren haben Zugriff auf das gesamte OpenAPI-Dokument. Sie können verwendet werden, um globale Änderungen am Dokument vorzunehmen.
  • Vorgangstransformatoren gelten jeweils für einen einzelnen Vorgang. Jeder einzelne Vorgang ist eine Kombination aus Pfad und HTTP-Methode. Sie können verwendet werden, um Parameter oder Antworten auf Endpunkten zu ändern.

Transformer können über den Aufruf der AddDocumentTransformer-Methode im OpenApiOptions-Objekt im Dokument registriert werden. Der folgende Codeschnipsel zeigt verschiedene Möglichkeiten zum Registrieren von Transformatoren im Dokument:

  • Registrieren eines Dokumenttransformators mithilfe eines Delegaten
  • Registrieren eines Dokumenttransformators mithilfe einer Instanz von IOpenApiDocumentTransformer
  • Registrieren eines Dokumenttransformators mithilfe eines DI-fähigen IOpenApiDocumentTransformer
  • Registrieren eines Vorgangstransformators mithilfe eines Delegaten
  • Registrieren eines Vorgangstransformators mithilfe einer Instanz von IOpenApiOperationTransformer.
  • Registrieren eines Vorgangstransformators mithilfe eines DI-fähigen IOpenApiOperationTransformer.
  • Registrieren eines Schematransformators mithilfe eines Delegaten.
  • Registrieren eines Schematransformators mithilfe einer Instanz von IOpenApiSchemaTransformer.
  • Registrieren eines Schematransformators mithilfe eines DI-fähigen IOpenApiSchemaTransformer.
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi(options =>
{
    options.AddDocumentTransformer((document, context, cancellationToken) 
                             => Task.CompletedTask);
    options.AddDocumentTransformer(new MyDocumentTransformer());
    options.AddDocumentTransformer<MyDocumentTransformer>();
    options.AddOperationTransformer((operation, context, cancellationToken)
                            => Task.CompletedTask);
    options.AddOperationTransformer(new MyOperationTransformer());
    options.AddOperationTransformer<MyOperationTransformer>();
    options.AddSchemaTransformer((schema, context, cancellationToken)
                            => Task.CompletedTask);
    options.AddSchemaTransformer(new MySchemaTransformer());
    options.AddSchemaTransformer<MySchemaTransformer>();
});

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

Ausführungsreihenfolge für Transformer

Transformer werden basierend auf der Registrierung in First-In-First-Out-Reihenfolge ausgeführt. Im folgenden Codeschnipsel hat der Dokumenttransformator Zugriff auf die vom Vorgangstransformator vorgenommenen Änderungen:

var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi(options =>
{
    options.AddOperationTransformer((operation, context, cancellationToken)
                                     => Task.CompletedTask);
    options.AddDocumentTransformer((document, context, cancellationToken)
                                     => Task.CompletedTask);
});

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

Verwenden von Dokumenttransformatoren

Dokumenttransformer haben Zugriff auf ein Kontextobjekt, das Folgendes umfasst:

  • den Namen des zu ändernden Dokuments
  • Die Liste der diesem Dokument zugeordneten ApiDescriptionGroups.
  • Der bei der Dokumentgenerierung verwendete IServiceProvider.

Dokumenttransformatoren können auch das generierte OpenAPI-Dokument ändern. Im folgenden Beispiel wird ein Dokumenttransformator veranschaulicht, der dem OpenAPI-Dokument einige Informationen zur API hinzufügt.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;

var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi(options =>
{
    options.AddDocumentTransformer((document, context, cancellationToken) =>
    {
        document.Info = new()
        {
            Title = "Checkout API",
            Version = "v1",
            Description = "API for processing checkouts from cart."
        };
        return Task.CompletedTask;
    });
});

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

Vom Dienst aktivierte Dokumenttransformatoren können Instanzen der Dokumentinstanz verwenden, um die App zu ändern. Im folgenden Beispiel wird ein Dokumenttransformator gezeigt, der den IAuthenticationSchemeProvider-Dienst auf Authentifizierungsebene verwendet. Er überprüft, ob alle Schemas für JWT-Bearer in der App registriert sind, und fügt sie auf der obersten Ebene des OpenAPI-Dokuments hinzu:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();

builder.Services.AddOpenApi(options =>
{
    options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
    public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
    {
        var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
        if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
        {
            var requirements = new Dictionary<string, OpenApiSecurityScheme>
            {
                ["Bearer"] = new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer", // "bearer" refers to the header name here
                    In = ParameterLocation.Header,
                    BearerFormat = "Json Web Token"
                }
            };
            document.Components ??= new OpenApiComponents();
            document.Components.SecuritySchemes = requirements;
        }
    }
}

Dokumenttransformatoren sind für die Dokumentinstanz eindeutig, der sie zugeordnet sind. Im folgenden Beispiel führt ein Transformator folgende Aktionen aus:

  • Er registriert authentifizierungsbezogene Anforderungen für das Dokument internal.
  • Er lässt das Dokument public unverändert.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();

builder.Services.AddOpenApi("internal", options =>
{
    options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});
builder.Services.AddOpenApi("public");

var app = builder.Build();

app.MapOpenApi();

app.MapGet("/world", () => "Hello world!")
    .WithGroupName("internal");
app.MapGet("/", () => "Hello universe!")
    .WithGroupName("public");

app.Run();

internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
    public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
    {
        var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
        if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
        {
            // Add the security scheme at the document level
            var requirements = new Dictionary<string, OpenApiSecurityScheme>
            {
                ["Bearer"] = new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer", // "bearer" refers to the header name here
                    In = ParameterLocation.Header,
                    BearerFormat = "Json Web Token"
                }
            };
            document.Components ??= new OpenApiComponents();
            document.Components.SecuritySchemes = requirements;

            // Apply it as a requirement for all operations
            foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
            {
                operation.Value.Security.Add(new OpenApiSecurityRequirement
                {
                    [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>()
                });
            }
        }
    }
}

Verwenden von Vorgangstransformatoren

Vorgänge sind eindeutige Kombinationen von HTTP-Pfaden und -Methoden in einem OpenAPI-Dokument. Vorgangstransformatoren sind bei folgenden Änderungen hilfreich:

  • Änderungen für jeden Endpunkt einer App oder
  • Bedingte Änderungen an bestimmten Routen

Vorgangstransformer haben Zugriff auf ein Kontextobjekt, das Folgendes enthält:

  • den Namen des Dokuments, zu dem der Vorgang gehört
  • ApiDescription, das dem Vorgang zugeordnet ist.
  • Der bei der Dokumentgenerierung verwendete IServiceProvider.

Beispielsweise fügt der folgende Vorgangstransformator 500 als Antwortstatuscode hinzu, der von allen Vorgängen im Dokument unterstützt wird.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();

builder.Services.AddOpenApi(options =>
{
    options.AddOperationTransformer((operation, context, cancellationToken) =>
    {
        operation.Responses.Add("500", new OpenApiResponse { Description = "Internal server error" });
        return Task.CompletedTask;
    });
});

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

Verwenden des generierten OpenAPI-Dokuments

OpenAPI-Dokumente können in ein breites Ökosystem vorhandener Tools für Tests, Dokumentationen und lokale Entwicklung eingebunden werden.

Verwenden von Swagger UI für lokale Ad-hoc-Tests

Standardmäßig bietet das Microsoft.AspNetCore.OpenApi-Paket keine integrierte Unterstützung für die Visualisierung des OpenAPI-Dokuments oder die Interaktion damit. Beliebte Tools zum Visualisieren oder Verwenden von OpenAPI-Dokumenten sind Swagger UI und ReDoc. Swagger UI und ReDoc können auf verschiedene Weise in eine App integriert werden. Editoren wie Visual Studio und VS Code bieten Erweiterungen und integrierte Features zum Testen von OpenAPI-Dokumenten.

Das Swashbuckle.AspNetCore.SwaggerUi-Paket enthält einige Webressourcen von Swagger UI für die Verwendung in Apps. Dieses Paket kann zum Rendern einer Benutzeroberfläche für das generierte Dokument verwendet werden. Um dies zu konfigurieren, installieren Sie das Swashbuckle.AspNetCore.SwaggerUi-Paket.

Aktivieren Sie die Middleware swagger-ui mit einem Verweis auf die zuvor registrierte OpenAPI-Route. Um die Veröffentlichung von Informationen und Sicherheitsrisiken zu minimieren, empfiehlt es sich, Swagger UI nur in Entwicklungsumgebungen zu aktivieren.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();
if (app.Environment.IsDevelopment())
{
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/openapi/v1.json", "v1");
    });

}

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

app.Run();

Verwenden von Scalar für die interaktive API-Dokumentation

Scalar ist eine interaktive Open-Source-Dokumentbenutzeroberfläche für OpenAPI. Skalar kann in den von ASP.NET Core bereitgestellten OpenAPI-Endpunkt integriert werden. Um Scalar zu konfigurieren, installieren Sie das Scalar.AspNetCore-Paket.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

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

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

app.Run();

Mit Linting generierte OpenAPI-Dokumente mit Spectral

Spectral ist ein Open-Source-Dokumentlinter für OpenAPI. Spectral kann in einen App-Build integriert werden, um die Qualität der generierten OpenAPI-Dokumente zu überprüfen. Installieren Sie Spectral gemäß der Anleitung zur Paketinstallation.

Um die Vorteile von Spectral nutzen zu können, installieren Sie das Paket Microsoft.Extensions.ApiDescription.Server, um die OpenAPI-Dokumentgenerierung zur Buildzeit zu ermöglichen.

Aktivieren Sie die Dokumentgenerierung zur Buildzeit, indem Sie die folgenden Eigenschaften in der .csproj-Datei Ihrer App festlegen:

<PropertyGroup>
    <OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
    <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>

Führen Sie dotnet build aus, um das Dokument zu generieren.

dotnet build

Erstellen Sie eine .spectral.yml-Datei mit dem folgenden Inhalt:

extends: ["spectral:oas"]

Führen Sie spectral lint für die generierte Datei aus.

spectral lint WebMinOpenApi.json
...

The output shows any issues with the OpenAPI document.

```output
1:1  warning  oas3-api-servers       OpenAPI "servers" must be present and non-empty array.
3:10  warning  info-contact           Info object must have "contact" object.                        info
3:10  warning  info-description       Info "description" must be present and non-empty string.       info
9:13  warning  operation-description  Operation "description" must be present and non-empty string.  paths./.get
9:13  warning  operation-operationId  Operation must have "operationId".                             paths./.get

✖ 5 problems (0 errors, 5 warnings, 0 infos, 0 hints)

Minimal-APIs bieten über das Paket Microsoft.AspNetCore.OpenApi integrierte Unterstützung für das Generieren von Informationen zu Endpunkten in einer App. Für das Verfügbarmachen der generierten OpenAPI-Definition über eine visuelle Benutzeroberfläche ist ein Paket eines Drittanbieters erforderlich. Informationen zur Unterstützung von OpenAPI in controllerbasierten APIs finden Sie in der .NET 9-Version dieses Artikels.

Der folgende Code ist aus der minimalen Web-API-Vorlage von ASP.NET Core generiert und verwendet OpenAPI:

using Microsoft.AspNetCore.OpenApi;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

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")
.WithOpenApi();

app.Run();

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

Im hervorgehobenen Code oben:

  • Microsoft.AspNetCore.OpenApi wird im nächsten Abschnitt erläutert.
  • AddEndpointsApiExplorer : Konfiguriert die App so, dass sie den API-Explorer verwendet, um Endpunkte mit Standardanmerkungen zu ermitteln und zu beschreiben. WithOpenApi setzt die Übereinstimmung von Standardanmerkungen, die vom API-Explorer generiert werden, mit denen, die aus dem Microsoft.AspNetCore.OpenApi Paket erstellt wurden, außer Kraft.
  • UseSwaggerfügt die Swagger Middleware hinzu.
  • „UseSwaggerUI“ ermöglicht eine eingebettete Version des Swagger UI-Tools.
  • WithName: Der IEndpointNameMetadata auf dem Endpunkt wird für die Linkgenerierung verwendet und wird als Vorgangs-ID in der OpenAPI-Spezifikation des angegebenen Endpunkts behandelt.
  • WithOpenApi wird später im Artikel erläutert.

Microsoft.AspNetCore.OpenApi NuGet-Paket

ASP.NET Core stellt das Microsoft.AspNetCore.OpenApi Paket bereit, um mit OpenAPI-Spezifikationen für Endpunkte zu interagieren. Das Paket verhält sich wie eine Verknüpfung zwischen den OpenAPI-Modellen, die im Microsoft.AspNetCore.OpenApi Paket definiert sind, und den Endpunkten, die in minimalen APIs definiert sind. Das Paket stellt eine API bereit, welche die Parameter, Antworten und Metadaten eines Endpunkts untersucht, um einen OpenAPI-Anmerkungstyp zu erstellen, der zum Beschreiben eines Endpunkts verwendet wird.

Microsoft.AspNetCore.OpenApi wird als PackageReference zu einer Projektdatei hinzugefügt:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>    
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.*-*" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>

Wenn Swashbuckle.AspNetCore mit Microsoft.AspNetCore.OpenApi verwendet wird, muss Swashbuckle.AspNetCore 6.4.0 oder höher verwendet werden. Microsoft.OpenApi 1.4.3 oder höher ist erforderlich, um Kopierkonstruktoren in WithOpenApi-Aufrufen zu verwenden.

Hinzufügen von OpenAPI-Anmerkungen zu Endpunkten über WithOpenApi

Durch Aufrufen von WithOpenApi für den Endpunkt werden die Metadaten des Endpunkts ergänzt. Diese Metadaten können:

  • In Drittanbieterpaketen wie Swashbuckle.AspNetCore verarbeitet werden.
  • Auf der Benutzeroberfläche von Swagger oder in YAML oder JSON angezeigt werden, die zum Definieren der API erstellt wurden.
app.MapPost("/todoitems/{id}", async (int id, Todo todo, TodoDb db) =>
{
    todo.Id = id;
    db.Todos.Add(todo);
    await db.SaveChangesAsync();

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

Ändern der OpenAPI-Anmerkung in WithOpenApi

Die WithOpenApi Methode akzeptiert eine Funktion, die benutzt werden kann, um die OpenAPI-Anmerkung zu verändern. Im folgenden Code wird beispielsweise eine Beschreibung zum ersten Parameter des Endpunkts hinzugefügt:

app.MapPost("/todo2/{id}", async (int id, Todo todo, TodoDb db) =>
{
    todo.Id = id;
    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi(generatedOperation =>
{
    var parameter = generatedOperation.Parameters[0];
    parameter.Description = "The ID associated with the created Todo";
    return generatedOperation;
});

Hinzufügen von Vorgangs-IDs zu OpenAPI

Vorgangs-IDs werden verwendet, um einen bestimmten Endpunkt in OpenAPI eindeutig zu identifizieren. Mit der Erweiterungsmethode WithName können Sie die für eine Methode verwendete Vorgangs-ID festlegen.

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

Alternativ kann die OperationId-Eigenschaft auch direkt für die OpenAPI-Anmerkung festgelegt werden.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        OperationId = "GetTodos"
    });

Hinzufügen von Tags zur OpenAPI-Beschreibung

OpenAPI unterstützt Tagobjekte zum Kategorisieren von Vorgängen. Diese Tags werden in der Regel zum Gruppieren von Vorgängen auf der Swagger-Benutzeroberfläche verwendet. Diese Tags können einem Vorgang hinzugefügt werden, indem Sie die Erweiterungsmethode WithTags für den Endpunkt mit den gewünschten Tags aufrufen.

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

Alternativ kann die Liste der OpenApiTags über die OpenAPI-Anmerkung mittels der Erweiterungsmethode WithOpenApi festgelegt werden.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        Tags = new List<OpenApiTag> { new() { Name = "Todos" } }
    });

Hinzufügen einer Endpunktzusammenfassung oder -beschreibung

Die Endpunktzusammenfassung und -beschreibung kann durch Aufrufen der WithOpenApi-Erweiterungsmethode hinzugefügt werden. Im folgenden Code werden die Zusammenfassungen direkt in der OpenAPI-Anmerkung festgelegt.

app.MapGet("/todoitems2", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        Summary = "This is a summary",
        Description = "This is a description"
    });

Ausschließen der OpenAPI-Beschreibung

Im folgenden Beispiel wird der /skipme-Endpunkt von der Generierung einer OpenAPI-Beschreibung ausgeschlossen:

using Microsoft.AspNetCore.OpenApi;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

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

app.UseHttpsRedirection();

app.MapGet("/swag", () => "Hello Swagger!")
    .WithOpenApi();
app.MapGet("/skipme", () => "Skipping Swagger.")
                    .ExcludeFromDescription();

app.Run();

Markieren einer API als veraltet

Wenn Sie einen Endpunkt als veraltet markieren möchten, legen Sie für die OpenAPI-Anmerkung die Eigenschaft Deprecated fest.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        Deprecated = true
    });

Beschreiben von Antworttypen

OpenAPI unterstützt die Bereitstellung einer Beschreibung der von einer API zurückgegebenen Antworten. Minimal-APIs unterstützen drei Strategien zum Festlegen des Antworttyps eines Endpunkts:

Mit der Erweiterungsmethode Produces können einem Endpunkt Produces-Metadaten hinzugefügt werden. Wenn keine Parameter angegeben werden, füllt die Erweiterungsmethode die Metadaten für den Zieltyp mit dem Statuscode 200 und dem Inhaltstyp application/json auf.

app
    .MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .Produces<IList<Todo>>();

Die Verwendung von TypedResults in der Implementierung des Routenhandlers eines Endpunkts schließt automatisch die Metadaten des Antworttyps für den Endpunkt ein. Der nachstehende Code versieht beispielsweise den Endpunkt automatisch mit einer Antwort unter dem Statuscode 200 mit dem Inhaltstyp application/json.

app.MapGet("/todos", async (TodoDb db) =>
{
    var todos = await db.Todos.ToListAsync());
    return TypedResults.Ok(todos);
});

Festlegen von Antworten für ProblemDetails

Beim Festlegen des Antworttyps für Endpunkte, die eine ProblemDetails-Antwort zurückgeben können, kann die Erweiterungsmethode ProducesProblem, ProducesValidationProblem oder TypedResults.Problem verwendet werden, um den entsprechenden Kommentar zu den Metadaten des Endpunkts hinzuzufügen. Beachten Sie, dass die Erweiterungsmethoden ProducesProblem und ProducesValidationProblem nicht mit Routengruppen in .NET 8 und früher verwendet werden können.

Wenn es keine expliziten Anmerkungen gibt, die mittels einer der oben genannten Strategien bereitgestellt werden, versucht das Framework, einen Standardantworttyp zu bestimmen, indem es die Signatur der Antwort untersucht. Diese Standardantwort wird unter dem Statuscode 200 in der OpenAPI-Definition eingetragen.

Mehrere Antworttypen

Wenn ein Endpunkt verschiedene Antworttypen in verschiedenen Szenarien zurückgeben kann, können Sie Metadaten auf folgende Weise bereitstellen:

  • Rufen Sie die Produces-Erweiterungsmethode mehrmals auf, wie im folgenden Beispiel gezeigt:

    app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
             await db.Todos.FindAsync(id) 
             is Todo todo
             ? Results.Ok(todo) 
             : Results.NotFound())
       .Produces<Todo>(StatusCodes.Status200OK)
       .Produces(StatusCodes.Status404NotFound);
    
  • Verwenden Sie Results<TResult1,TResult2,TResultN> in der Signatur und TypedResults im Textkörper des Handlers, wie im folgenden Beispiel gezeigt:

    app.MapGet("/book{id}", Results<Ok<Book>, NotFound> (int id, List<Book> bookList) =>
    {
        return bookList.FirstOrDefault((i) => i.Id == id) is Book book
         ? TypedResults.Ok(book)
         : TypedResults.NotFound();
    });
    

    Die Results<TResult1,TResult2,TResultN>-Uniontypen deklarieren, dass ein Routenhandler mehrere IResult implementierende konkrete Typen zurückgibt, und jeder dieser Typen, die IEndpointMetadataProvider implementieren, trägt zu den Metadaten des Endpunkts bei.

    Die Union-Typen implementieren implizite Umwandlungsoperatoren. Diese Operatoren ermöglichen dem Compiler, die in den generischen Argumenten angegebenen Typen automatisch in eine Instanz des Union-Typs zu konvertieren. Diese Fähigkeit hat den zusätzlichen Vorteil, dass zur Kompilierungszeit überprüft wird, ob ein Routenhandler nur die Ergebnisse zurückgibt, die er deklariert. Der Versuch, einen Typ zurückzugeben, der nicht als eines der generischen Argumente für Results<TResult1,TResult2,TResultN> deklariert wurde, führt zu einem Kompilierungsfehler.

Beschreiben von Anforderungstext und -parametern

Neben der Beschreibung der Typen, die von einem Endpunkt zurückgegeben werden, unterstützt OpenAPI auch Anmerkungen zu Eingaben, die von einer API genutzt werden. Diese Eingaben lassen sich in zwei Kategorien einteilen:

  • Parameter, die im Pfad, in der Abfragezeichenfolge, in den Headern oder cookies enthalten sind
  • Daten, die als Teil des Anforderungstexts übermittelt werden

Das Framework leitet die Typen der Anforderungsparameter im Pfad, in der Abfrage und in der Headerzeichenfolge automatisch aus der Signatur des Routenhandlers ab.

Um den Typ der Eingaben zu definieren, die als Anforderungstext übermittelt werden, konfigurieren Sie die Eigenschaften mit der Accepts-Methode, um den Objekt- und Inhaltstyp zu definieren, die vom Anforderungshandler erwartet werden. Im nachstehenden Beispiel akzeptiert der Endpunkt ein Todo-Objekt im Anforderungstext mit dem erwarteten Inhaltstyp application/xml.

app.MapPost("/todos/{id}", (int id, Todo todo) => ...)
  .Accepts<Todo>("application/xml");

Zusätzlich zur Erweiterungsmethode Accepts kann ein Parametertyp durch Implementierung der IEndpointParameterMetadataProvider-Schnittstelle seine eigene Anmerkung beschreiben. Beispielsweise fügt der folgende Todo-Typ eine Anmerkung hinzu, die einen Anforderungstext mit dem Inhaltstyp application/xml erfordert.

public class Todo : IEndpointParameterMetadataProvider
{
    public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
    {
        builder.Metadata.Add(new ConsumesAttribute(typeof(Todo), isOptional: false, "application/xml"));
    }
}

Falls keine explizite Anmerkung angegeben wird, versucht das Framework, den Standardanforderungstyp zu bestimmen, wenn es einen Anforderungstextparameter im Endpunkthandler gibt. Der Rückschluss verwendet die folgende Heuristik, um die Anmerkung zu generieren:

  • Anforderungstextparameter, die über das Attribut [FromForm] aus einem Formular gelesen werden, werden mit dem Inhaltstyp multipart/form-data beschrieben.
  • Alle anderen Anforderungstextparameter werden mit dem Inhaltstyp application/json beschrieben.
  • Der Anforderungstext wird als optional behandelt, wenn er Nullwerte zulässt oder die AllowEmpty-Eigenschaft für das FromBody-Attribut festgelegt ist.

Unterstützung der API-Versionsverwaltung

Minimal-APIs unterstützen über das Paket Asp.Versioning.Http die API-Versionsverwaltung. Beispiele für die Konfiguration der Versionsverwaltung mit Minimal-APIs finden Sie im Repository der API-Versionsverwaltung.

ASP.NET Core OpenAPI-Quellcode auf GitHub

Weitere Ressourcen

Eine minimale API-App kann die OpenAPI-Spezifikation für Routenhandler unter Verwendung von Swashbuckle beschreiben.

Informationen zur Unterstützung von OpenAPI in controllerbasierten APIs finden Sie in der .NET 9-Version dieses Artikels.

Der folgende Code ist eine typische ASP.NET Core-App mit OpenAPI-Unterstützung:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new() { Title = builder.Environment.ApplicationName,
                               Version = "v1" });
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger(); // UseSwaggerUI Protected by if (env.IsDevelopment())
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json",
                                    $"{builder.Environment.ApplicationName} v1"));
}

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

app.Run();

Ausschließen der OpenAPI-Beschreibung

Im folgenden Beispiel wird der /skipme-Endpunkt von der Generierung einer OpenAPI-Beschreibung ausgeschlossen:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(); // UseSwaggerUI Protected by if (env.IsDevelopment())
}

app.MapGet("/swag", () => "Hello Swagger!");
app.MapGet("/skipme", () => "Skipping Swagger.")
                    .ExcludeFromDescription();

app.Run();

Beschreiben von Antworttypen

Im folgenden Beispiel werden die integrierten Ergebnistypen verwendet, um die Antwort anzupassen:

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

Hinzufügen von Vorgangs-IDs zur OpenAPI

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

Hinzufügen von Tags zur OpenAPI-Beschreibung

Im folgenden Code wird ein OpenAPI-Gruppierungstag verwendet:

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