Skip to content

Commit 656fe93

Browse files
committed
fix: dotnet#58329 merge multiple consumes content types into one operation
1 parent 335de67 commit 656fe93

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

src/OpenApi/src/Services/OpenApiDocumentService.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@ private async Task<Dictionary<OperationType, OpenApiOperation>> GetOperationsAsy
278278
};
279279

280280
_operationTransformerContextCache.TryAdd(description.ActionDescriptor.Id, operationContext);
281-
operations[description.GetOperationType()] = operation;
282281

283282
// Use index-based for loop to avoid allocating an enumerator with a foreach.
284283
for (var i = 0; i < operationTransformers.Length; i++)
@@ -295,6 +294,24 @@ private async Task<Dictionary<OperationType, OpenApiOperation>> GetOperationsAsy
295294
{
296295
await endpointOperationTransformer.TransformAsync(operation, operationContext, cancellationToken);
297296
}
297+
298+
var operationType = description.GetOperationType();
299+
if (
300+
operations.TryGetValue(operationType, out var existingOperation) &&
301+
existingOperation.RequestBody?.Content is not null &&
302+
operation.RequestBody is { Content.Count: > 0 }
303+
)
304+
{
305+
// Merge additional accepted content types into the existing operation.
306+
foreach (var body in operation.RequestBody.Content)
307+
{
308+
existingOperation.RequestBody.Content.Add(body);
309+
}
310+
}
311+
else
312+
{
313+
operations[operationType] = operation;
314+
}
298315
}
299316
return operations;
300317
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiDocumentService/OpenApiDocumentServiceTests.RequestBody.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,40 @@ await VerifyOpenApiDocument(builder, document =>
259259
});
260260
}
261261

262+
/// <summary>
263+
/// Tests documented behavior at https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-9.0#define-supported-request-content-types-with-the-consumes-attribute-1
264+
/// </summary>
265+
[Fact]
266+
public async Task GetRequestBody_HandlesMultipleAcceptedContentType()
267+
{
268+
// Arrange
269+
var builder = CreateBuilder();
270+
271+
// Act
272+
builder.MapPost("/", [Consumes("application/json")] (TodoWithDueDate name) => { });
273+
builder.MapPost("/", [Consumes("application/x-www-form-urlencoded")] ([FromForm] TodoWithDueDate name) => { });
274+
275+
// Assert
276+
await VerifyOpenApiDocument(builder, document =>
277+
{
278+
var paths = Assert.Single(document.Paths.Values);
279+
var operation = paths.Operations[OperationType.Post];
280+
Assert.NotNull(operation.RequestBody);
281+
282+
Assert.Collection(operation.RequestBody.Content,
283+
pair =>
284+
{
285+
Assert.Equal("application/json", pair.Key);
286+
Assert.Equal("TodoWithDueDate", pair.Value.Schema.Annotations["x-schema-id"]);
287+
},
288+
pair =>
289+
{
290+
Assert.Equal("application/x-www-form-urlencoded", pair.Key);
291+
Assert.Equal("TodoWithDueDate", pair.Value.Schema.Annotations["x-schema-id"]);
292+
});
293+
});
294+
}
295+
262296
[Fact]
263297
public async Task GetRequestBody_HandlesJsonBody()
264298
{

0 commit comments

Comments
 (0)