Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Transformatoren für OpenAPI-Dokumente
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
Transformatoren sind in drei 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.
- Schematransformatoren gelten für jedes Schema im Dokument. Diese können verwendet werden, um das Schema von Anforderungs- oder Antworttexten oder geschachtelten Schemata 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 Sie einen Schematransformator 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();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", () => "Hello world!");
app.Run();
Ausführungsreihenfolge für Transformer
Transformatoren werden in der folgenden Reihenfolge betrieben.
- Schematransformatoren werden ausgeführt, wenn ein Schema für das Dokument registriert ist. Sie werden in der Reihenfolge ausgeführt, in der sie hinzugefügt werden. Alle Schemas werden dem Dokument hinzugefügt, bevor eine Vorgangsverarbeitung erfolgt, sodass Schematransformatoren vor Betriebstransformatoren ausgeführt werden.
- Vorgangstransformatoren werden ausgeführt, wenn dem Dokument ein Vorgang hinzugefügt wird. Sie werden in der Reihenfolge ausgeführt, in der sie hinzugefügt werden. Alle Operationen werden dem Dokument hinzugefügt, bevor Dokumenttransformatoren ausgeführt werden.
- Dokumenttransformatoren werden ausgeführt, wenn das Dokument generiert wird. Dies ist der letzte Durchlauf des Dokuments, und alle Vorgänge und Schemas werden an diesem Punkt hinzugefügt.
- Wenn eine App so konfiguriert ist, dass mehrere OpenAPI-Dokumente generiert werden, werden Transformatoren für jedes Dokument unabhängig voneinander ausgeführt.
Beispiel: Im folgenden Codeausschnitt:
-
SchemaTransformer2
wird ausgeführt und hat Zugriff auf die Änderungen, die vonSchemaTransformer1
vorgenommen wurden. - Beide
OperationTransformer1
undOperationTransformer2
haben Zugriff auf die Änderungen, die von beiden Schematransformatoren für die Typen vorgenommen werden, die an dem Vorgang beteiligt sind, den sie ausführen. -
OperationTransformer2
wird nachOperationTransformer1
ausgeführt, sodass es Zugriff auf die Änderungen hat, die vonOperationTransformer1
vorgenommen wurden. - Sowohl
DocumentTransformer1
als auchDocumentTransformer2
werden ausgeführt, nachdem alle Operationen und Schemata dem Dokument hinzugefügt wurden, sodass sie Zugriff auf alle Änderungen haben, die von den Transformatoren für Operationen und Schemata vorgenommen wurden. -
DocumentTransformer2
wird nachDocumentTransformer1
ausgeführt, sodass es Zugriff auf die Änderungen hat, die vonDocumentTransformer1
vorgenommen wurden.
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer<DocumentTransformer1>();
options.AddSchemaTransformer<SchemaTransformer1>();
options.AddDocumentTransformer<DocumentTransformer2>();
options.AddOperationTransformer<OperationTransformer1>();
options.AddSchemaTransformer<SchemaTransformer2>();
options.AddOperationTransformer<OperationTransformer2>();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
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
- Das ApiDescriptionGroups, das mit diesem Dokument verbunden ist.
- 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();
if (app.Environment.IsDevelopment())
{
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();
if (app.Environment.IsDevelopment())
{
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();
if (app.Environment.IsDevelopment())
{
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
- Bedingt auf bestimmte Routen angewandt
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();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", () => "Hello world!");
app.Run();
Verwenden von Schematransformatoren
Schemas sind die Datenmodelle, die in Anforderungs- und Antworttextkörpern in einem OpenAPI-Dokument verwendet werden. Schematransformatoren sind nützlich, wenn eine Änderung vorgenommen wird:
- Sollte an jedem Schema im Dokument vorgenommen werden oder
- bedingt auf bestimmte Schemata angewendet werden.
Schematransformatoren haben Zugriff auf ein Kontextobjekt, das Folgendes enthält:
- Der Name des Dokuments, zu dem das Schema gehört.
- die JSON-Typinformationen, die dem Zielschema zugeordnet sind.
- Der bei der Dokumentgenerierung verwendete IServiceProvider.
Der folgende Schematransformator setzt zum Beispiel das format
von Dezimaltypen auf decimal
statt auf double
:
using Microsoft.AspNetCore.OpenApi;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options => {
// Schema transformer to set the format of decimal to 'decimal'
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.JsonTypeInfo.Type == typeof(decimal))
{
schema.Format = "decimal";
}
return Task.CompletedTask;
});
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", () => new Body { Amount = 1.1m });
app.Run();
public class Body {
public decimal Amount { get; set; }
}
Unterstützung für die Generierung von OpenApiSchemas in Transformatoren
Entwickler können ein Schema für einen C#-Typ mit derselben Logik wie ASP.NET Core OpenAPI-Dokumentgenerierung generieren und dem OpenAPI-Dokument hinzufügen. Das Schema kann dann an anderer Stelle im OpenAPI-Dokument referenziert werden. Diese Funktion ist ab .NET 10 verfügbar.
Der an Dokument-, Vorgangs- und Schematransformatoren übergebene Kontext enthält eine neue GetOrCreateSchemaAsync
Methode, mit der ein Schema für einen Typ generiert werden kann.
Diese Methode verfügt auch über einen optionalen ApiParameterDescription
Parameter, um zusätzliche Metadaten für das generierte Schema anzugeben.
Um das Hinzufügen des Schemas zum OpenAPI-Dokument zu unterstützen, wurde eine Document
Eigenschaft zu den Kontexten "Operation" und "Schematransformor" hinzugefügt. Auf diese Weise kann jeder Transformator dem OpenAPI-Dokument mithilfe der Methode des AddComponent
Dokuments ein Schema hinzufügen.
Beispiel
Um dieses Feature in einem Dokument, einem Vorgang oder einem Schematransformator zu verwenden, erstellen Sie das Schema mithilfe der GetOrCreateSchemaAsync
im Kontext bereitgestellten Methode, und fügen Sie es mithilfe der Methode des AddComponent
Dokuments dem OpenAPI-Dokument hinzu.
builder.Services.AddOpenApi(options =>
{
options.AddOperationTransformer(async (operation, context, cancellationToken) =>
{
// Generate schema for error responses
var errorSchema = await context.GetOrCreateSchemaAsync(typeof(ProblemDetails), null, cancellationToken);
context.Document?.AddComponent("Error", errorSchema);
operation.Responses ??= new OpenApiResponses();
// Add a "4XX" response to the operation with the newly created schema
operation.Responses["4XX"] = new OpenApiResponse
{
Description = "Bad Request",
Content = new Dictionary<string, OpenApiMediaType>
{
["application/problem+json"] = new OpenApiMediaType
{
Schema = new OpenApiSchemaReference("Error", context.Document)
}
}
};
});
});
Anpassen der Schemawiederverwendung
Nachdem alle Transformatoren angewendet wurden, macht das Framework einen Durchlauf über das Dokument, um bestimmte Schemas in den Abschnitt components.schemas
zu übertragen und ersetzt sie durch $ref
-Verweise auf das übertragene Schema.
Dadurch wird die Größe des Dokuments reduziert und das Lesen erleichtert.
Die Details dieser Verarbeitung sind kompliziert und können sich in zukünftigen Versionen von .NET ändern, aber im Allgemeinen:
- Schemas für Klassen-/Datensatz-/Strukturtypen werden durch einen
$ref
zu einem Schema incomponents.schemas
ersetzt, wenn sie mehr als einmal im Dokument angezeigt werden. - Schemas für primitive Typen und Standardauflistungen bleiben inline.
- Schemas für Enumerationstypen werden immer mit einer
$ref
durch ein Schema in „components.schemas” ersetzt.
In der Regel ist der Name des Schemas in components.schemas
der Name des Klassen-/Datensatz-/Strukturtyps, aber unter bestimmten Umständen muss ein anderer Name verwendet werden.
ASP.NET Core ermöglicht es Ihnen, anzupassen, welche Schemas durch ein $ref
in einem Schema in components.schemas
mithilfe der Eigenschaft CreateSchemaReferenceId von OpenApiOptions ersetzt werden.
Diese Eigenschaft ist ein Delegat, der ein JsonTypeInfo-Objekt nimmt und den Namen des Schemas in components.schemas
zurückgibt, das für diesen Typ verwendet werden soll.
Das Framework bietet eine Standardimplementierung des Delegaten CreateDefaultSchemaReferenceId, der den Namen des Typs verwendet. Sie können diesen jedoch durch Ihre eigene Implementierung ersetzen.
Als einfaches Beispiel für diese Anpassung können Sie festlegen, dass immer Inline-Enumerationsschemas verwendet werden. Dies wird erreicht, indem CreateSchemaReferenceId auf einen Delegaten gesetzt wird, der für Enumerationstypen null zurückgibt und sonst den Wert aus der Standardimplementierung liefert. Der folgende Code veranschaulicht folgendes:
builder.Services.AddOpenApi(options =>
{
// Always inline enum schemas
options.CreateSchemaReferenceId = (type) =>
type.Type.IsEnum ? null : OpenApiOptions.CreateDefaultSchemaReferenceId(type);
});
Zusätzliche Ressourcen
Transformatoren für OpenAPI-Dokumente
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
Transformatoren sind in drei 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.
- Schematransformatoren gelten für jedes Schema im Dokument. Diese können verwendet werden, um das Schema von Anforderungs- oder Antworttexten oder geschachtelten Schemata 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 Sie einen Schematransformator 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();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", () => "Hello world!");
app.Run();
Ausführungsreihenfolge für Transformer
Transformatoren werden wie folgt ausgeführt:
- Schematransformatoren werden ausgeführt, wenn ein Schema für das Dokument registriert ist. Schematransformatoren werden in der Reihenfolge ausgeführt, in der sie hinzugefügt wurden. Alle Schemas werden dem Dokument hinzugefügt, bevor eine Vorgangsverarbeitung erfolgt, sodass alle Schematransformatoren vor Vorgangstransformatoren ausgeführt werden.
- Vorgangstransformatoren werden ausgeführt, wenn dem Dokument ein Vorgang hinzugefügt wird. Betriebstransformatoren werden in der Reihenfolge ausgeführt, in der sie hinzugefügt wurden. Alle Vorgänge werden dem Dokument hinzugefügt, bevor Dokumenttransformatoren ausgeführt werden.
- Dokumenttransformatoren werden ausgeführt, wenn das Dokument generiert wird. Dies ist der letzte Durchlauf des Dokuments, und alle Vorgänge und Schemas wurden an diesem Punkt hinzugefügt.
- Wenn eine App so konfiguriert ist, dass mehrere OpenAPI-Dokumente generiert werden, werden Transformatoren für jedes Dokument unabhängig voneinander ausgeführt.
Beispiel: Im folgenden Codeausschnitt:
-
SchemaTransformer2
wird ausgeführt und hat Zugriff auf die Änderungen, die vonSchemaTransformer1
vorgenommen wurden. -
OperationTransformer1
undOperationTransformer2
haben Zugriff auf die Änderungen, die von beiden Schematransformatoren für die Typen vorgenommen wurden, die an dem Vorgang beteiligt sind, zu dem sie aufgerufen wurden, um ihn zu verarbeiten. -
OperationTransformer2
wird nachOperationTransformer1
ausgeführt, sodass es Zugriff auf die Änderungen hat, die vonOperationTransformer1
vorgenommen wurden. - Sowohl
DocumentTransformer1
als auchDocumentTransformer2
werden ausgeführt, nachdem alle Operationen und Schemata dem Dokument hinzugefügt wurden, sodass sie Zugriff auf alle Änderungen haben, die von den Transformatoren für Operationen und Schemata vorgenommen wurden. -
DocumentTransformer2
wird nachDocumentTransformer1
ausgeführt, sodass es Zugriff auf die Änderungen hat, die vonDocumentTransformer1
vorgenommen wurden.
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer<DocumentTransformer1>();
options.AddSchemaTransformer<SchemaTransformer1>();
options.AddDocumentTransformer<DocumentTransformer2>();
options.AddOperationTransformer<OperationTransformer1>();
options.AddSchemaTransformer<SchemaTransformer2>();
options.AddOperationTransformer<OperationTransformer2>();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
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
- Das ApiDescriptionGroups, das mit diesem Dokument verbunden ist.
- 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();
if (app.Environment.IsDevelopment())
{
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();
if (app.Environment.IsDevelopment())
{
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();
if (app.Environment.IsDevelopment())
{
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
- Bedingt auf bestimmte Routen angewandt
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();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", () => "Hello world!");
app.Run();
Verwenden von Schematransformatoren
Schemas sind die Datenmodelle, die in Anforderungs- und Antworttextkörpern in einem OpenAPI-Dokument verwendet werden. Schematransformatoren sind nützlich, wenn eine Änderung vorgenommen wird:
- Sollte an jedem Schema im Dokument vorgenommen werden oder
- bedingt auf bestimmte Schemata angewendet werden.
Schematransformatoren haben Zugriff auf ein Kontextobjekt, das Folgendes enthält:
- Der Name des Dokuments, zu dem das Schema gehört.
- die JSON-Typinformationen, die dem Zielschema zugeordnet sind.
- Der bei der Dokumentgenerierung verwendete IServiceProvider.
Der folgende Schematransformator setzt zum Beispiel das format
von Dezimaltypen auf decimal
statt auf double
:
using Microsoft.AspNetCore.OpenApi;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options => {
// Schema transformer to set the format of decimal to 'decimal'
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.JsonTypeInfo.Type == typeof(decimal))
{
schema.Format = "decimal";
}
return Task.CompletedTask;
});
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", () => new Body { Amount = 1.1m });
app.Run();
public class Body {
public decimal Amount { get; set; }
}
Anpassen der Schemawiederverwendung
Nachdem alle Transformatoren angewendet wurden, macht das Framework einen Durchlauf über das Dokument, um bestimmte Schemas in den Abschnitt components.schemas
zu übertragen und ersetzt sie durch $ref
-Verweise auf das übertragene Schema.
Dadurch wird die Größe des Dokuments reduziert und das Lesen erleichtert.
Die Details dieser Verarbeitung sind kompliziert und können sich in zukünftigen Versionen von .NET ändern, aber im Allgemeinen:
- Schemas für Klassen-/Datensatz-/Strukturtypen werden durch einen
$ref
zu einem Schema incomponents.schemas
ersetzt, wenn sie mehr als einmal im Dokument angezeigt werden. - Schemas für primitive Typen und Standardauflistungen bleiben inline.
- Schemas für Enumerationstypen werden immer mit einer
$ref
durch ein Schema in „components.schemas” ersetzt.
In der Regel ist der Name des Schemas in components.schemas
der Name des Klassen-/Datensatz-/Strukturtyps, aber unter bestimmten Umständen muss ein anderer Name verwendet werden.
ASP.NET Core ermöglicht es Ihnen, anzupassen, welche Schemas durch ein $ref
in einem Schema in components.schemas
mithilfe der Eigenschaft CreateSchemaReferenceId von OpenApiOptions ersetzt werden.
Diese Eigenschaft ist ein Delegat, der ein JsonTypeInfo-Objekt nimmt und den Namen des Schemas in components.schemas
zurückgibt, das für diesen Typ verwendet werden soll.
Das Framework bietet eine Standardimplementierung des Delegaten CreateDefaultSchemaReferenceId, der den Namen des Typs verwendet. Sie können diesen jedoch durch Ihre eigene Implementierung ersetzen.
Als einfaches Beispiel für diese Anpassung können Sie festlegen, dass immer Inline-Enumerationsschemas verwendet werden. Dies wird erreicht, indem CreateSchemaReferenceId auf einen Delegaten gesetzt wird, der für Enumerationstypen null zurückgibt und sonst den Wert aus der Standardimplementierung liefert. Der folgende Code zeigt, wie Dies geschieht:
builder.Services.AddOpenApi(options =>
{
// Always inline enum schemas
options.CreateSchemaReferenceId = (type) =>
type.Type.IsEnum ? null : OpenApiOptions.CreateDefaultSchemaReferenceId(type);
});