Skip to content

Commit 0e1746b

Browse files
authored
Reset OpenApiSchemaTransformerContext before each invocation (#56905)
* Reset OpenApiSchemaTransformerContext before each invocation * Only call UpdateJsonTypeInfo once
1 parent c323953 commit 0e1746b

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ internal async Task ApplySchemaTransformersAsync(OpenApiSchema schema, Type type
155155
};
156156
for (var i = 0; i < _openApiOptions.SchemaTransformers.Count; i++)
157157
{
158+
// Reset context object to base state before running each transformer.
158159
var transformer = _openApiOptions.SchemaTransformers[i];
159160
// If the transformer is a type-based transformer, we need to initialize and finalize it
160161
// once in the context of the top-level assembly and not the child properties we are invoking
@@ -164,7 +165,7 @@ internal async Task ApplySchemaTransformersAsync(OpenApiSchema schema, Type type
164165
var initializedTransformer = typeBasedTransformer.InitializeTransformer(serviceProvider);
165166
try
166167
{
167-
await InnerApplySchemaTransformersAsync(schema, jsonTypeInfo, context, initializedTransformer, cancellationToken);
168+
await InnerApplySchemaTransformersAsync(schema, jsonTypeInfo, null, context, initializedTransformer, cancellationToken);
168169
}
169170
finally
170171
{
@@ -173,17 +174,19 @@ internal async Task ApplySchemaTransformersAsync(OpenApiSchema schema, Type type
173174
}
174175
else
175176
{
176-
await InnerApplySchemaTransformersAsync(schema, jsonTypeInfo, context, transformer, cancellationToken);
177+
await InnerApplySchemaTransformersAsync(schema, jsonTypeInfo, null, context, transformer, cancellationToken);
177178
}
178179
}
179180
}
180181

181182
private async Task InnerApplySchemaTransformersAsync(OpenApiSchema schema,
182183
JsonTypeInfo jsonTypeInfo,
184+
JsonPropertyInfo? jsonPropertyInfo,
183185
OpenApiSchemaTransformerContext context,
184186
IOpenApiSchemaTransformer transformer,
185187
CancellationToken cancellationToken = default)
186188
{
189+
context.UpdateJsonTypeInfo(jsonTypeInfo, jsonPropertyInfo);
187190
await transformer.TransformAsync(schema, context, cancellationToken);
188191

189192
// Only apply transformers on polymorphic schemas where we can resolve the derived
@@ -194,31 +197,28 @@ private async Task InnerApplySchemaTransformersAsync(OpenApiSchema schema,
194197
foreach (var derivedType in jsonTypeInfo.PolymorphismOptions.DerivedTypes)
195198
{
196199
var derivedJsonTypeInfo = _jsonSerializerOptions.GetTypeInfo(derivedType.DerivedType);
197-
context.UpdateJsonTypeInfo(derivedJsonTypeInfo, null);
198200
if (schema.AnyOf.Count <= anyOfIndex)
199201
{
200202
break;
201203
}
202-
await InnerApplySchemaTransformersAsync(schema.AnyOf[anyOfIndex], derivedJsonTypeInfo, context, transformer, cancellationToken);
204+
await InnerApplySchemaTransformersAsync(schema.AnyOf[anyOfIndex], derivedJsonTypeInfo, null, context, transformer, cancellationToken);
203205
anyOfIndex++;
204206
}
205207
}
206208

207209
if (schema.Items is not null)
208210
{
209211
var elementTypeInfo = _jsonSerializerOptions.GetTypeInfo(jsonTypeInfo.ElementType!);
210-
context.UpdateJsonTypeInfo(elementTypeInfo, null);
211-
await InnerApplySchemaTransformersAsync(schema.Items, elementTypeInfo, context, transformer, cancellationToken);
212+
await InnerApplySchemaTransformersAsync(schema.Items, elementTypeInfo, null, context, transformer, cancellationToken);
212213
}
213214

214215
if (schema.Properties is { Count: > 0 })
215216
{
216217
foreach (var propertyInfo in jsonTypeInfo.Properties)
217218
{
218-
context.UpdateJsonTypeInfo(_jsonSerializerOptions.GetTypeInfo(propertyInfo.PropertyType), propertyInfo);
219219
if (schema.Properties.TryGetValue(propertyInfo.Name, out var propertySchema))
220220
{
221-
await InnerApplySchemaTransformersAsync(propertySchema, _jsonSerializerOptions.GetTypeInfo(propertyInfo.PropertyType), context, transformer, cancellationToken);
221+
await InnerApplySchemaTransformersAsync(propertySchema, _jsonSerializerOptions.GetTypeInfo(propertyInfo.PropertyType), propertyInfo, context, transformer, cancellationToken);
222222
}
223223
}
224224
}

src/OpenApi/test/Transformers/SchemaTransformerTests.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,28 @@ public async Task SchemaTransformer_CanAccessTypeAndParameterDescriptionForParam
1919
builder.MapPost("/todo", (Todo todo) => { });
2020

2121
var options = new OpenApiOptions();
22+
var firstInvocationOnSecondTransformer = true;
2223
options.AddSchemaTransformer((schema, context, cancellationToken) =>
24+
{
25+
ValidateContext(context);
26+
return Task.CompletedTask;
27+
})
28+
.AddSchemaTransformer((schema, context, cancellationToken) =>
29+
{
30+
// Coverage for https://github.com/dotnet/aspnetcore/issues/56899
31+
if (firstInvocationOnSecondTransformer)
32+
{
33+
Assert.Equal(typeof(Todo), context.JsonTypeInfo.Type);
34+
firstInvocationOnSecondTransformer = false;
35+
}
36+
// Rest of the state is still consistent
37+
ValidateContext(context);
38+
return Task.CompletedTask;
39+
});
40+
41+
await VerifyOpenApiDocument(builder, options, document => { });
42+
43+
static void ValidateContext(OpenApiSchemaTransformerContext context)
2344
{
2445
if (context.JsonPropertyInfo == null)
2546
{
@@ -42,10 +63,7 @@ public async Task SchemaTransformer_CanAccessTypeAndParameterDescriptionForParam
4263
{
4364
Assert.Equal(typeof(DateTime), context.JsonTypeInfo.Type);
4465
}
45-
return Task.CompletedTask;
46-
});
47-
48-
await VerifyOpenApiDocument(builder, options, document => { });
66+
}
4967
}
5068

5169
[Fact]

0 commit comments

Comments
 (0)