Skip to content

Commit b341f8c

Browse files
authored
Add APIs for OpenAPI document transformers (#54935)
* Add APIs for OpenAPI document transformers * Address feedback * Update doc comments * Address more feedback * Handle service lifetimes correctly in activated transformers * Handle disposable transformers * Benchmark on transformer count * Fix up disposable code and improve paths perf * Remove unused imports in SharedTypes for RDG tests * Clean up benchmarks and TryGetCachedOperationTransformerContext
1 parent 72f4723 commit b341f8c

28 files changed

+1076
-21
lines changed

AspNetCore.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuthen
17901790
EndProject
17911791
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "src\OpenApi\sample\Sample.csproj", "{6DEC24A8-A166-432F-8E3B-58FFCDA92F52}"
17921792
EndProject
1793+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.OpenApi.Microbenchmarks", "src\OpenApi\perf\Microsoft.AspNetCore.OpenApi.Microbenchmarks.csproj", "{CF082AD5-E513-4A27-A6C7-3767E04D6205}"
1794+
EndProject
17931795
Global
17941796
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17951797
Debug|Any CPU = Debug|Any CPU
@@ -10807,6 +10809,22 @@ Global
1080710809
{6DEC24A8-A166-432F-8E3B-58FFCDA92F52}.Release|x64.Build.0 = Release|Any CPU
1080810810
{6DEC24A8-A166-432F-8E3B-58FFCDA92F52}.Release|x86.ActiveCfg = Release|Any CPU
1080910811
{6DEC24A8-A166-432F-8E3B-58FFCDA92F52}.Release|x86.Build.0 = Release|Any CPU
10812+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10813+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|Any CPU.Build.0 = Debug|Any CPU
10814+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|arm64.ActiveCfg = Debug|Any CPU
10815+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|arm64.Build.0 = Debug|Any CPU
10816+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|x64.ActiveCfg = Debug|Any CPU
10817+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|x64.Build.0 = Debug|Any CPU
10818+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|x86.ActiveCfg = Debug|Any CPU
10819+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Debug|x86.Build.0 = Debug|Any CPU
10820+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|Any CPU.ActiveCfg = Release|Any CPU
10821+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|Any CPU.Build.0 = Release|Any CPU
10822+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|arm64.ActiveCfg = Release|Any CPU
10823+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|arm64.Build.0 = Release|Any CPU
10824+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|x64.ActiveCfg = Release|Any CPU
10825+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|x64.Build.0 = Release|Any CPU
10826+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|x86.ActiveCfg = Release|Any CPU
10827+
{CF082AD5-E513-4A27-A6C7-3767E04D6205}.Release|x86.Build.0 = Release|Any CPU
1081010828
EndGlobalSection
1081110829
GlobalSection(SolutionProperties) = preSolution
1081210830
HideSolutionNode = FALSE
@@ -11691,6 +11709,7 @@ Global
1169111709
{433F91E4-E39D-4EB0-B798-2998B3969A2C} = {6126DCE4-9692-4EE2-B240-C65743572995}
1169211710
{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13} = {6126DCE4-9692-4EE2-B240-C65743572995}
1169311711
{6DEC24A8-A166-432F-8E3B-58FFCDA92F52} = {2299CCD8-8F9C-4F2B-A633-9BF4DA81022B}
11712+
{CF082AD5-E513-4A27-A6C7-3767E04D6205} = {2299CCD8-8F9C-4F2B-A633-9BF4DA81022B}
1169411713
EndGlobalSection
1169511714
GlobalSection(ExtensibilityGlobals) = postSolution
1169611715
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

src/Http/Http.Extensions/test/RequestDelegateGenerator/SharedTypes.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
using Microsoft.Extensions.DependencyInjection;
1313
using Microsoft.AspNetCore.Mvc;
1414
using Microsoft.AspNetCore.Routing;
15-
using System.Diagnostics.CodeAnalysis;
16-
using Microsoft.Diagnostics.Runtime.Interop;
1715

1816
namespace Microsoft.AspNetCore.Http.Generators.Tests;
1917

src/OpenApi/OpenApi.slnf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"src\\Http\\Routing\\src\\Microsoft.AspNetCore.Routing.csproj",
1010
"src\\OpenApi\\src\\Microsoft.AspNetCore.OpenApi.csproj",
1111
"src\\OpenApi\\test\\Microsoft.AspNetCore.OpenApi.Tests.csproj",
12-
"src\\OpenApi\\sample\\Sample.csproj"
12+
"src\\OpenApi\\sample\\Sample.csproj",
13+
"src\\OpenApi\\perf\\Microsoft.AspNetCore.OpenApi.Microbenchmarks.csproj"
1314
]
1415
}
1516
}

src/OpenApi/perf/AssemblyInfo.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<PreserveCompilationContext>true</PreserveCompilationContext>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Reference Include="BenchmarkDotNet" />
11+
<Reference Include="Microsoft.AspNetCore" />
12+
<Reference Include="Microsoft.AspNetCore.OpenApi" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\test\Microsoft.AspNetCore.OpenApi.Tests.csproj" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" />
21+
</ItemGroup>
22+
23+
</Project>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using BenchmarkDotNet.Attributes;
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Routing;
7+
using Microsoft.OpenApi.Models;
8+
9+
namespace Microsoft.AspNetCore.OpenApi.Microbenchmarks;
10+
11+
/// <summary>
12+
/// The following benchmarks are used to assess the memory and performance
13+
/// impact of different types of transformers. In particular, we want to
14+
/// measure the impact of (a) context-object creation and caching and (b)
15+
/// enumerator usage when processing operations in a given document.
16+
/// </summary>
17+
public class TransformersBenchmark : OpenApiDocumentServiceTestBase
18+
{
19+
[Params(10, 100, 1000)]
20+
public int TransformerCount { get; set; }
21+
22+
private readonly IEndpointRouteBuilder _builder = CreateBuilder();
23+
private readonly OpenApiOptions _options = new OpenApiOptions();
24+
private OpenApiDocumentService _documentService;
25+
26+
[GlobalSetup(Target = nameof(OperationTransformerAsDelegate))]
27+
public void OperationTransformerAsDelegate_Setup()
28+
{
29+
_builder.MapGet("/", () => { });
30+
for (var i = 0; i <= TransformerCount; i++)
31+
{
32+
_options.UseOperationTransformer((operation, context, token) =>
33+
{
34+
operation.Description = "New Description";
35+
return Task.CompletedTask;
36+
});
37+
}
38+
_documentService = CreateDocumentService(_builder, _options);
39+
}
40+
41+
[GlobalSetup(Target = nameof(ActivatedDocumentTransformer))]
42+
public void ActivatedDocumentTransformer_Setup()
43+
{
44+
_builder.MapGet("/", () => { });
45+
for (var i = 0; i <= TransformerCount; i++)
46+
{
47+
_options.UseTransformer<ActivatedTransformer>();
48+
}
49+
_documentService = CreateDocumentService(_builder, _options);
50+
}
51+
52+
[GlobalSetup(Target = nameof(DocumentTransformerAsDelegate))]
53+
public void DocumentTransformerAsDelegate_Delegate()
54+
{
55+
_builder.MapGet("/", () => { });
56+
for (var i = 0; i <= TransformerCount; i++)
57+
{
58+
_options.UseTransformer((document, context, token) =>
59+
{
60+
document.Info.Description = "New Description";
61+
return Task.CompletedTask;
62+
});
63+
}
64+
_documentService = CreateDocumentService(_builder, _options);
65+
}
66+
67+
[Benchmark]
68+
public async Task OperationTransformerAsDelegate()
69+
{
70+
await _documentService.GetOpenApiDocumentAsync();
71+
}
72+
73+
[Benchmark]
74+
public async Task ActivatedDocumentTransformer()
75+
{
76+
await _documentService.GetOpenApiDocumentAsync();
77+
}
78+
79+
[Benchmark]
80+
public async Task DocumentTransformerAsDelegate()
81+
{
82+
await _documentService.GetOpenApiDocumentAsync();
83+
}
84+
85+
private class ActivatedTransformer : IOpenApiDocumentTransformer
86+
{
87+
public Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
88+
{
89+
document.Info.Description = "Info Description";
90+
return Task.CompletedTask;
91+
}
92+
}
93+
}

src/OpenApi/sample/Program.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using Microsoft.OpenApi.Models;
5+
using Sample.Transformers;
6+
47
var builder = WebApplication.CreateBuilder(args);
58

6-
builder.Services.AddOpenApi("v1");
7-
builder.Services.AddOpenApi("v2");
9+
builder.Services.AddAuthentication().AddJwtBearer();
10+
11+
builder.Services.AddOpenApi("v1", options =>
12+
{
13+
options.AddHeader("X-Version", "1.0");
14+
options.UseTransformer<BearerSecuritySchemeTransformer>();
15+
});
16+
builder.Services.AddOpenApi("v2", options => {
17+
options.UseTransformer(new AddContactTransformer());
18+
options.UseTransformer((document, context, token) => {
19+
document.Info.License = new OpenApiLicense { Name = "MIT" };
20+
return Task.CompletedTask;
21+
});
22+
});
823

924
var app = builder.Build();
1025

src/OpenApi/sample/Sample.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
<ItemGroup>
1010
<Reference Include="Microsoft.AspNetCore" />
11+
<Reference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
1112
<Reference Include="Microsoft.AspNetCore.Hosting" />
1213
<Reference Include="Microsoft.AspNetCore.OpenApi" />
1314
<Reference Include="Microsoft.AspNetCore.Http" />
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.Authentication;
5+
using Microsoft.AspNetCore.OpenApi;
6+
using Microsoft.OpenApi.Models;
7+
8+
namespace Sample.Transformers;
9+
10+
public sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
11+
{
12+
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
13+
{
14+
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
15+
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
16+
{
17+
var requirements = new Dictionary<string, OpenApiSecurityScheme>
18+
{
19+
["Bearer"] = new OpenApiSecurityScheme
20+
{
21+
Type = SecuritySchemeType.Http,
22+
Scheme = "bearer", // "bearer" refers to the header name here
23+
In = ParameterLocation.Header,
24+
BearerFormat = "Json Web Token"
25+
}
26+
};
27+
document.Components ??= new OpenApiComponents();
28+
document.Components.SecuritySchemes = requirements;
29+
}
30+
}
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.OpenApi;
5+
using Microsoft.OpenApi.Models;
6+
7+
namespace Sample.Transformers;
8+
9+
public sealed class AddContactTransformer : IOpenApiDocumentTransformer
10+
{
11+
public Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
12+
{
13+
document.Info.Contact = new OpenApiContact
14+
{
15+
Name = "OpenAPI Enthusiast",
16+
17+
};
18+
return Task.CompletedTask;
19+
}
20+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.OpenApi;
5+
using Microsoft.OpenApi.Models;
6+
using Microsoft.OpenApi.Any;
7+
using Microsoft.OpenApi.Extensions;
8+
9+
namespace Sample.Transformers;
10+
11+
public static class OperationTransformers
12+
{
13+
public static OpenApiOptions AddHeader(this OpenApiOptions options, string headerName, string defaultValue)
14+
{
15+
return options.UseOperationTransformer((operation, context, cancellationToken) =>
16+
{
17+
var schema = OpenApiTypeMapper.MapTypeToOpenApiPrimitiveType(typeof(string));
18+
schema.Default = new OpenApiString(defaultValue);
19+
operation.Parameters.Add(new OpenApiParameter
20+
{
21+
Name = headerName,
22+
In = ParameterLocation.Header,
23+
Schema = schema
24+
});
25+
return Task.CompletedTask;
26+
});
27+
}
28+
}

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();
46+
var document = await documentService.GetOpenApiDocumentAsync(context.RequestAborted);
4747
var documentOptions = options.Get(documentName);
4848
using var output = MemoryBufferWriter.Get();
4949
using var writer = Utf8BufferTextWriter.Get(output);

src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
<ItemGroup>
2929
<InternalsVisibleTo Include="Microsoft.AspNetCore.OpenApi.Tests" />
30+
<InternalsVisibleTo Include="Microsoft.AspNetCore.OpenApi.Microbenchmarks" />
3031
</ItemGroup>
3132

3233
<ItemGroup>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,37 @@
11
#nullable enable
22
Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions
3+
Microsoft.AspNetCore.OpenApi.IOpenApiDocumentTransformer.TransformAsync(Microsoft.OpenApi.Models.OpenApiDocument! document, Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext! context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
4+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.Description.get -> Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription!
5+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.Description.init -> void
36
Microsoft.AspNetCore.OpenApi.OpenApiOptions
47
Microsoft.AspNetCore.OpenApi.OpenApiOptions.DocumentName.get -> string!
58
Microsoft.AspNetCore.OpenApi.OpenApiOptions.OpenApiOptions() -> void
69
Microsoft.AspNetCore.OpenApi.OpenApiOptions.OpenApiVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion
710
Microsoft.AspNetCore.OpenApi.OpenApiOptions.OpenApiVersion.set -> void
811
Microsoft.AspNetCore.OpenApi.OpenApiOptions.ShouldInclude.get -> System.Func<Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription!, bool>!
912
Microsoft.AspNetCore.OpenApi.OpenApiOptions.ShouldInclude.set -> void
13+
Microsoft.AspNetCore.OpenApi.OpenApiOptions.UseOperationTransformer(System.Func<Microsoft.OpenApi.Models.OpenApiOperation!, Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext!, System.Threading.CancellationToken, System.Threading.Tasks.Task!>! transformer) -> Microsoft.AspNetCore.OpenApi.OpenApiOptions!
14+
Microsoft.AspNetCore.OpenApi.OpenApiOptions.UseTransformer(Microsoft.AspNetCore.OpenApi.IOpenApiDocumentTransformer! transformer) -> Microsoft.AspNetCore.OpenApi.OpenApiOptions!
15+
Microsoft.AspNetCore.OpenApi.OpenApiOptions.UseTransformer(System.Func<Microsoft.OpenApi.Models.OpenApiDocument!, Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext!, System.Threading.CancellationToken, System.Threading.Tasks.Task!>! transformer) -> Microsoft.AspNetCore.OpenApi.OpenApiOptions!
16+
Microsoft.AspNetCore.OpenApi.OpenApiOptions.UseTransformer<TTransformerType>() -> Microsoft.AspNetCore.OpenApi.OpenApiOptions!
1017
Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions
1118
static Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions.MapOpenApi(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints, string! pattern = "/openapi/{documentName}.json") -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder!
1219
static Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
1320
static Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, string! documentName) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
1421
static Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, string! documentName, System.Action<Microsoft.AspNetCore.OpenApi.OpenApiOptions!>! configureOptions) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
1522
static Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<Microsoft.AspNetCore.OpenApi.OpenApiOptions!>! configureOptions) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
23+
Microsoft.AspNetCore.OpenApi.IOpenApiDocumentTransformer
24+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext
25+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.ApplicationServices.get -> System.IServiceProvider!
26+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.ApplicationServices.init -> void
27+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.DescriptionGroups.get -> System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionGroup!>!
28+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.DescriptionGroups.init -> void
29+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.DocumentName.get -> string!
30+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.DocumentName.init -> void
31+
Microsoft.AspNetCore.OpenApi.OpenApiDocumentTransformerContext.OpenApiDocumentTransformerContext() -> void
32+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext
33+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.ApplicationServices.get -> System.IServiceProvider!
34+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.ApplicationServices.init -> void
35+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.DocumentName.get -> string!
36+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.DocumentName.init -> void
37+
Microsoft.AspNetCore.OpenApi.OpenApiOperationTransformerContext.OpenApiOperationTransformerContext() -> void

src/OpenApi/src/Services/OpenApiConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ internal static class OpenApiConstants
88
internal const string DefaultDocumentName = "v1";
99
internal const string DefaultOpenApiVersion = "1.0.0";
1010
internal const string DefaultOpenApiRoute = "/openapi/{documentName}.json";
11+
internal const string DescriptionId = "x-aspnetcore-id";
1112
}

0 commit comments

Comments
 (0)