Skip to content

Commit 40a9912

Browse files
committed
Fix up disposable code and improve paths perf
1 parent 604498c commit 40a9912

File tree

4 files changed

+36
-74
lines changed

4 files changed

+36
-74
lines changed

src/OpenApi/src/Services/OpenApiDocumentService.cs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,7 @@ private async Task ApplyTransformersAsync(OpenApiDocument document, Cancellation
7070
for (var i = 0; i < _options.DocumentTransformers.Count; i++)
7171
{
7272
var transformer = _options.DocumentTransformers[i];
73-
try
74-
{
75-
await transformer.TransformAsync(document, documentTransformerContext, cancellationToken);
76-
}
77-
finally
78-
{
79-
if (transformer is IDisposable disposable)
80-
{
81-
disposable.Dispose();
82-
}
83-
if (transformer is IAsyncDisposable asyncDisposable)
84-
{
85-
await asyncDisposable.DisposeAsync();
86-
}
87-
if (transformer is TypeBasedOpenApiDocumentTransformer typedTransformer)
88-
{
89-
await typedTransformer.DisposeAsync();
90-
}
91-
}
73+
await transformer.TransformAsync(document, documentTransformerContext, cancellationToken);
9274
}
9375
}
9476

src/OpenApi/src/Transformers/DelegateOpenApiDocumentTransformer.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@ namespace Microsoft.AspNetCore.OpenApi;
99

1010
internal sealed class DelegateOpenApiDocumentTransformer : IOpenApiDocumentTransformer
1111
{
12+
// Since there's a finite set of operation types that can be included in a given
13+
// OpenApiPaths, we can pre-allocate an array of these types and use a direct
14+
// lookup on the OpenApiPaths dictionary to avoid allocating an enumerator
15+
// over the KeyValuePairs in OpenApiPaths.
16+
private static readonly OperationType[] _operationTypes = [
17+
OperationType.Get,
18+
OperationType.Post,
19+
OperationType.Put,
20+
OperationType.Delete,
21+
OperationType.Options,
22+
OperationType.Head,
23+
OperationType.Patch,
24+
OperationType.Trace
25+
];
1226
private readonly Func<OpenApiDocument, OpenApiDocumentTransformerContext, CancellationToken, Task>? _documentTransformer;
1327
private readonly Func<OpenApiOperation, OpenApiOperationTransformerContext, CancellationToken, Task>? _operationTransformer;
1428

@@ -34,8 +48,14 @@ public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransf
3448
var documentService = context.ApplicationServices.GetRequiredKeyedService<OpenApiDocumentService>(context.DocumentName);
3549
foreach (var pathItem in document.Paths.Values)
3650
{
37-
foreach (var operation in pathItem.Operations.Values)
51+
for (var i = 0; i < _operationTypes.Length; i++)
3852
{
53+
var operationType = _operationTypes[i];
54+
if (!pathItem.Operations.TryGetValue(operationType, out var operation))
55+
{
56+
continue;
57+
}
58+
3959
if (operation.Extensions.TryGetValue(OpenApiConstants.DescriptionId, out var descriptionIdExtension) &&
4060
descriptionIdExtension is OpenApiString { Value: var descriptionId } &&
4161
documentService.TryGetCachedOperationTransformerContext(descriptionId, out var operationContext))

src/OpenApi/src/Transformers/TypeBasedOpenApiDocumentTransformer.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ namespace Microsoft.AspNetCore.OpenApi;
1010
internal sealed class TypeBasedOpenApiDocumentTransformer(Type transformerType) : IOpenApiDocumentTransformer
1111
{
1212
private readonly ObjectFactory _transformerFactory = ActivatorUtilities.CreateFactory(transformerType, []);
13-
private IOpenApiDocumentTransformer? _transformer;
1413

15-
public ValueTask DisposeAsync()
14+
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
1615
{
17-
if (_transformer is IAsyncDisposable asyncDisposable)
16+
var transformer = _transformerFactory.Invoke(context.ApplicationServices, []) as IOpenApiDocumentTransformer;
17+
Debug.Assert(transformer != null, $"The type {transformerType} does not implement {nameof(IOpenApiDocumentTransformer)}.");
18+
try
1819
{
19-
return asyncDisposable.DisposeAsync();
20+
await transformer.TransformAsync(document, context, cancellationToken);
2021
}
21-
if (_transformer is IDisposable disposable)
22+
finally
2223
{
23-
disposable.Dispose();
24+
if (transformer is IAsyncDisposable asyncDisposable)
25+
{
26+
await asyncDisposable.DisposeAsync();
27+
}
28+
else if (transformer is IDisposable disposable)
29+
{
30+
disposable.Dispose();
31+
}
2432
}
25-
return ValueTask.CompletedTask;
26-
}
27-
28-
public Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
29-
{
30-
_transformer = _transformerFactory.Invoke(context.ApplicationServices, []) as IOpenApiDocumentTransformer;
31-
Debug.Assert(_transformer != null, $"The type {transformerType} does not implement {nameof(IOpenApiDocumentTransformer)}.");
32-
return _transformer.TransformAsync(document, context, cancellationToken);
3333
}
3434
}

src/OpenApi/test/Transformers/DocumentTransformerTests.cs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -122,46 +122,6 @@ await VerifyOpenApiDocument(builder, options, document =>
122122
});
123123
}
124124

125-
[Fact]
126-
public async Task DocumentTransformer_SupportsDisposableInstanceTransformer()
127-
{
128-
var builder = CreateBuilder();
129-
130-
builder.MapGet("/todo", () => { });
131-
builder.MapGet("/user", () => { });
132-
133-
var options = new OpenApiOptions();
134-
var transformer = new DisposableTransformer();
135-
options.UseTransformer(transformer);
136-
137-
Assert.False(transformer.Disposed);
138-
await VerifyOpenApiDocument(builder, options, document =>
139-
{
140-
Assert.Equal("Info Description", document.Info.Description);
141-
});
142-
Assert.True(transformer.Disposed);
143-
}
144-
145-
[Fact]
146-
public async Task DocumentTransformer_SupportsAsyncDisposableInstanceTransformer()
147-
{
148-
var builder = CreateBuilder();
149-
150-
builder.MapGet("/todo", () => { });
151-
builder.MapGet("/user", () => { });
152-
153-
var options = new OpenApiOptions();
154-
var transformer = new AsyncDisposableTransformer();
155-
options.UseTransformer(transformer);
156-
157-
Assert.False(transformer.Disposed);
158-
await VerifyOpenApiDocument(builder, options, document =>
159-
{
160-
Assert.Equal("Info Description", document.Info.Description);
161-
});
162-
Assert.True(transformer.Disposed);
163-
}
164-
165125
[Fact]
166126
public async Task DocumentTransformer_SupportsDisposableActivatedTransformer()
167127
{

0 commit comments

Comments
 (0)