Freigeben über


Erste Schritte mit Microsoft.AspNetCore.OpenApi

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

  • ist mit nativem AOT kompatibel.
  • nutzt JSON-Schemaunterstützung, die von System.Text.Json bereitgestellt wird.
  • stellt eine Transformator-API zum Ändern generierter Dokumente bereit.
  • unterstützt die Verwaltung mehrerer OpenAPI-Dokumente in einer einzigen App.

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

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.

Bedeutung von Dokumentnamen

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

Optionen zum Anpassen der OpenAPI-Dokumentgenerierung

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

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");

Hinweis: Es ist möglich, aber nicht empfohlen, den Routenparameter documentName aus der Endpunktroute zu entfernen. 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.

Anpassen von OpenAPI-Endpunkten mit Endpunktmetadaten

Die folgende Liste zeigt die Endpunktmetadaten zum Anpassen des generierten OpenAPI-Dokuments:

Weitere Informationen zum Anpassen des generierten OpenAPI-Dokuments durch Ändern von Endpunktmetadaten finden Sie unter Verwenden von OpenAPI in Minimal-API-Apps.

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 UseTransformer-Aufruf des OpenApiOptions-Objekts 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
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi(options =>
{
    options.UseTransformer((document, context, cancellationToken) 
                             => Task.CompletedTask);
    options.UseTransformer(new MyDocumentTransformer());
    options.UseTransformer<MyDocumentTransformer>();
    options.UseOperationTransformer((operation, context, cancellationToken)
                            => Task.CompletedTask);
});

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.UseOperationTransformer((operation, context, cancellationToken)
                                     => Task.CompletedTask);
    options.UseTransformer((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.UseTransformer((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.UseTransformer<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.UseTransformer<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.UseOperationTransformer((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)