Skip to content

Commit a97352c

Browse files
authored
Fix OpenAPI transformer lifetimes and disposal (#57253)
* Fix OpenAPI transformer lifetimes and disposal * React to feedback * Avoid nullable collections
1 parent 477666a commit a97352c

18 files changed

+936
-157
lines changed

src/OpenApi/OpenApi.generated.sln

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.5.002.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "sample\Sample.csproj", "{27EF80D8-4A11-44F1-BDBB-8C0F6E7085F4}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OpenApi", "src\Microsoft.AspNetCore.OpenApi.csproj", "{E2CD734D-7E40-4E0C-9662-1D5B5B331146}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{87EC42C6-E18C-4DD2-9AD2-416195A50848}"
11+
EndProject
12+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OpenApi.Tests", "test\Microsoft.AspNetCore.OpenApi.Tests\Microsoft.AspNetCore.OpenApi.Tests.csproj", "{8441A115-BF5D-47C9-BE1E-2BFF27BA24F2}"
13+
EndProject
14+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{1C3FBADB-D913-467C-8E1E-7E87F342C5EC}"
15+
EndProject
16+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OpenApi.Microbenchmarks", "perf\Microbenchmarks\Microsoft.AspNetCore.OpenApi.Microbenchmarks.csproj", "{47BA0F58-A9BE-42D8-9B2E-EA2D4F1F72D7}"
17+
EndProject
18+
Global
19+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
20+
Debug|Any CPU = Debug|Any CPU
21+
Release|Any CPU = Release|Any CPU
22+
EndGlobalSection
23+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
24+
{27EF80D8-4A11-44F1-BDBB-8C0F6E7085F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25+
{27EF80D8-4A11-44F1-BDBB-8C0F6E7085F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
26+
{27EF80D8-4A11-44F1-BDBB-8C0F6E7085F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
27+
{27EF80D8-4A11-44F1-BDBB-8C0F6E7085F4}.Release|Any CPU.Build.0 = Release|Any CPU
28+
{E2CD734D-7E40-4E0C-9662-1D5B5B331146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29+
{E2CD734D-7E40-4E0C-9662-1D5B5B331146}.Debug|Any CPU.Build.0 = Debug|Any CPU
30+
{E2CD734D-7E40-4E0C-9662-1D5B5B331146}.Release|Any CPU.ActiveCfg = Release|Any CPU
31+
{E2CD734D-7E40-4E0C-9662-1D5B5B331146}.Release|Any CPU.Build.0 = Release|Any CPU
32+
{8441A115-BF5D-47C9-BE1E-2BFF27BA24F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{8441A115-BF5D-47C9-BE1E-2BFF27BA24F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{8441A115-BF5D-47C9-BE1E-2BFF27BA24F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
35+
{8441A115-BF5D-47C9-BE1E-2BFF27BA24F2}.Release|Any CPU.Build.0 = Release|Any CPU
36+
{47BA0F58-A9BE-42D8-9B2E-EA2D4F1F72D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37+
{47BA0F58-A9BE-42D8-9B2E-EA2D4F1F72D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
38+
{47BA0F58-A9BE-42D8-9B2E-EA2D4F1F72D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
39+
{47BA0F58-A9BE-42D8-9B2E-EA2D4F1F72D7}.Release|Any CPU.Build.0 = Release|Any CPU
40+
EndGlobalSection
41+
GlobalSection(SolutionProperties) = preSolution
42+
HideSolutionNode = FALSE
43+
EndGlobalSection
44+
GlobalSection(NestedProjects) = preSolution
45+
{8441A115-BF5D-47C9-BE1E-2BFF27BA24F2} = {87EC42C6-E18C-4DD2-9AD2-416195A50848}
46+
{47BA0F58-A9BE-42D8-9B2E-EA2D4F1F72D7} = {1C3FBADB-D913-467C-8E1E-7E87F342C5EC}
47+
EndGlobalSection
48+
GlobalSection(ExtensibilityGlobals) = postSolution
49+
SolutionGuid = {DA0E25AF-669B-4D4B-9FCF-D0E56478E8F9}
50+
EndGlobalSection
51+
EndGlobal

src/OpenApi/perf/Microbenchmarks/GenerationBenchmarks.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.AspNetCore.Builder;
66
using Microsoft.AspNetCore.Http;
77
using Microsoft.AspNetCore.Routing;
8+
using Microsoft.Extensions.DependencyInjection;
89

910
namespace Microsoft.AspNetCore.OpenApi.Microbenchmarks;
1011

@@ -22,6 +23,7 @@ public class GenerationBenchmarks : OpenApiDocumentServiceTestBase
2223
private readonly IEndpointRouteBuilder _builder = CreateBuilder();
2324
private readonly OpenApiOptions _options = new OpenApiOptions();
2425
private OpenApiDocumentService _documentService;
26+
private IServiceProvider _serviceProvider;
2527

2628
[GlobalSetup(Target = nameof(GenerateDocument))]
2729
public void OperationTransformerAsDelegate_Setup()
@@ -34,11 +36,12 @@ public void OperationTransformerAsDelegate_Setup()
3436
_builder.MapDelete($"/{i}", (string id) => Results.NoContent());
3537
}
3638
_documentService = CreateDocumentService(_builder, _options);
39+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
3740
}
3841

3942
[Benchmark]
4043
public async Task GenerateDocument()
4144
{
42-
await _documentService.GetOpenApiDocumentAsync();
45+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
4346
}
4447
}

src/OpenApi/perf/Microbenchmarks/TransformersBenchmark.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using BenchmarkDotNet.Attributes;
55
using Microsoft.AspNetCore.Builder;
66
using Microsoft.AspNetCore.Routing;
7+
using Microsoft.Extensions.DependencyInjection;
78
using Microsoft.OpenApi.Any;
89
using Microsoft.OpenApi.Models;
910

@@ -23,6 +24,7 @@ public class TransformersBenchmark : OpenApiDocumentServiceTestBase
2324
private readonly IEndpointRouteBuilder _builder = CreateBuilder();
2425
private readonly OpenApiOptions _options = new();
2526
private OpenApiDocumentService _documentService;
27+
private IServiceProvider _serviceProvider;
2628

2729
[GlobalSetup(Target = nameof(ActivatedOperationTransformer))]
2830
public void ActivatedOperationTransformer_Setup()
@@ -33,6 +35,7 @@ public void ActivatedOperationTransformer_Setup()
3335
_options.AddOperationTransformer<OperationTransformer>();
3436
}
3537
_documentService = CreateDocumentService(_builder, _options);
38+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
3639
}
3740

3841
[GlobalSetup(Target = nameof(OperationTransformerAsDelegate))]
@@ -48,6 +51,7 @@ public void OperationTransformerAsDelegate_Setup()
4851
});
4952
}
5053
_documentService = CreateDocumentService(_builder, _options);
54+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
5155
}
5256

5357
[GlobalSetup(Target = nameof(ActivatedDocumentTransformer))]
@@ -59,6 +63,7 @@ public void ActivatedDocumentTransformer_Setup()
5963
_options.AddDocumentTransformer<DocumentTransformer>();
6064
}
6165
_documentService = CreateDocumentService(_builder, _options);
66+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
6267
}
6368

6469
[GlobalSetup(Target = nameof(DocumentTransformerAsDelegate))]
@@ -74,6 +79,7 @@ public void DocumentTransformerAsDelegate_Delegate()
7479
});
7580
}
7681
_documentService = CreateDocumentService(_builder, _options);
82+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
7783
}
7884

7985
[GlobalSetup(Target = nameof(ActivatedSchemaTransformer))]
@@ -85,6 +91,7 @@ public void ActivatedSchemaTransformer_Setup()
8591
_options.AddSchemaTransformer<SchemaTransformer>();
8692
}
8793
_documentService = CreateDocumentService(_builder, _options);
94+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
8895
}
8996

9097
[GlobalSetup(Target = nameof(SchemaTransformerAsDelegate))]
@@ -107,42 +114,43 @@ public void SchemaTransformer_Setup()
107114
});
108115
}
109116
_documentService = CreateDocumentService(_builder, _options);
117+
_serviceProvider = _builder.ServiceProvider.CreateScope().ServiceProvider;
110118
}
111119

112120
[Benchmark]
113121
public async Task ActivatedOperationTransformer()
114122
{
115-
await _documentService.GetOpenApiDocumentAsync();
123+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
116124
}
117125

118126
[Benchmark]
119127
public async Task OperationTransformerAsDelegate()
120128
{
121-
await _documentService.GetOpenApiDocumentAsync();
129+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
122130
}
123131

124132
[Benchmark]
125133
public async Task ActivatedDocumentTransformer()
126134
{
127-
await _documentService.GetOpenApiDocumentAsync();
135+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
128136
}
129137

130138
[Benchmark]
131139
public async Task DocumentTransformerAsDelegate()
132140
{
133-
await _documentService.GetOpenApiDocumentAsync();
141+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
134142
}
135143

136144
[Benchmark]
137145
public async Task ActivatedSchemaTransformer()
138146
{
139-
await _documentService.GetOpenApiDocumentAsync();
147+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
140148
}
141149

142150
[Benchmark]
143151
public async Task SchemaTransformerAsDelegate()
144152
{
145-
await _documentService.GetOpenApiDocumentAsync();
153+
await _documentService.GetOpenApiDocumentAsync(_serviceProvider);
146154
}
147155

148156
private class DocumentTransformer : IOpenApiDocumentTransformer

src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder e
4343
}
4444
else
4545
{
46-
var document = await documentService.GetOpenApiDocumentAsync(context.RequestAborted);
46+
var document = await documentService.GetOpenApiDocumentAsync(context.RequestServices, context.RequestAborted);
4747
var documentOptions = options.Get(documentName);
4848
using var output = MemoryBufferWriter.Get();
4949
using var writer = Utf8BufferTextWriter.Get(output);

src/OpenApi/src/Services/OpenApiDocumentProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public async Task GenerateAsync(string documentName, TextWriter writer, OpenApiS
4444
// document to a file. See https://github.com/microsoft/OpenAPI.NET/issues/421 for
4545
// more info.
4646
var targetDocumentService = serviceProvider.GetRequiredKeyedService<OpenApiDocumentService>(documentName);
47-
var document = await targetDocumentService.GetOpenApiDocumentAsync();
47+
using var scopedService = serviceProvider.CreateScope();
48+
var document = await targetDocumentService.GetOpenApiDocumentAsync(scopedService.ServiceProvider);
4849
var jsonWriter = new OpenApiJsonWriter(writer);
4950
document.Serialize(jsonWriter, openApiSpecVersion);
5051
}

0 commit comments

Comments
 (0)