@@ -262,22 +262,33 @@ private async Task<Dictionary<OperationType, OpenApiOperation>> GetOperationsAsy
262262 CancellationToken cancellationToken )
263263 {
264264 var operations = new Dictionary < OperationType , OpenApiOperation > ( ) ;
265- foreach ( var description in descriptions )
265+ foreach ( var opTypeDescriptions in descriptions . GroupBy ( d => d . GetOperationType ( ) ) )
266266 {
267- var operation = await GetOperationAsync ( description , document , scopedServiceProvider , schemaTransformers , cancellationToken ) ;
267+ var operationType = opTypeDescriptions . Key ;
268+
269+ // `description` is the first description for a given Route + HttpMethod.
270+ // There may be additional descriptions if the endpoint has additional definitions
271+ // with different [Consumes] definitions. We merge in the bodies of these additional endpoints,
272+ // but currently don't merge any other parts of the definition.
273+ IReadOnlyList < ApiDescription > allDescriptions = [ .. opTypeDescriptions ] ;
274+ var description = allDescriptions . First ( ) ;
275+
276+ var operation = await GetOperationAsync ( allDescriptions , document , scopedServiceProvider , schemaTransformers , cancellationToken ) ;
268277 operation . Annotations ??= new Dictionary < string , object > ( ) ;
269278 operation . Annotations . Add ( OpenApiConstants . DescriptionId , description . ActionDescriptor . Id ) ;
270279
271280 var operationContext = new OpenApiOperationTransformerContext
272281 {
273282 DocumentName = documentName ,
274283 Description = description ,
284+ AllDescriptions = [ .. allDescriptions ] ,
275285 ApplicationServices = scopedServiceProvider ,
276286 Document = document ,
277287 SchemaTransformers = schemaTransformers
278288 } ;
279289
280290 _operationTransformerContextCache . TryAdd ( description . ActionDescriptor . Id , operationContext ) ;
291+ operations [ operationType ] = operation ;
281292
282293 // Use index-based for loop to avoid allocating an enumerator with a foreach.
283294 for ( var i = 0 ; i < operationTransformers . Length ; i ++ )
@@ -288,41 +299,25 @@ private async Task<Dictionary<OperationType, OpenApiOperation>> GetOperationsAsy
288299
289300 // Apply any endpoint-specific operation transformers registered via
290301 // the AddOpenApiOperationTransformer extension method.
291- var endpointOperationTransformers = description . ActionDescriptor . EndpointMetadata
292- . OfType < DelegateOpenApiOperationTransformer > ( ) ;
302+ var endpointOperationTransformers = allDescriptions
303+ . SelectMany ( d => d . ActionDescriptor . EndpointMetadata
304+ . OfType < DelegateOpenApiOperationTransformer > ( ) ) ;
293305 foreach ( var endpointOperationTransformer in endpointOperationTransformers )
294306 {
295307 await endpointOperationTransformer . TransformAsync ( operation , operationContext , cancellationToken ) ;
296308 }
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- }
315309 }
316310 return operations ;
317311 }
318312
319313 private async Task < OpenApiOperation > GetOperationAsync (
320- ApiDescription description ,
314+ IReadOnlyList < ApiDescription > descriptions ,
321315 OpenApiDocument document ,
322316 IServiceProvider scopedServiceProvider ,
323317 IOpenApiSchemaTransformer [ ] schemaTransformers ,
324318 CancellationToken cancellationToken )
325319 {
320+ var description = descriptions . First ( ) ;
326321 var tags = GetTags ( description , document ) ;
327322 var operation = new OpenApiOperation
328323 {
@@ -331,9 +326,30 @@ private async Task<OpenApiOperation> GetOperationAsync(
331326 Description = GetDescription ( description ) ,
332327 Responses = await GetResponsesAsync ( document , description , scopedServiceProvider , schemaTransformers , cancellationToken ) ,
333328 Parameters = await GetParametersAsync ( document , description , scopedServiceProvider , schemaTransformers , cancellationToken ) ,
334- RequestBody = await GetRequestBodyAsync ( document , description , scopedServiceProvider , schemaTransformers , cancellationToken ) ,
335329 Tags = tags ,
336330 } ;
331+
332+ foreach ( var bodyDescription in descriptions )
333+ {
334+ var requestBody = await GetRequestBodyAsync ( document , bodyDescription , scopedServiceProvider , schemaTransformers , cancellationToken ) ;
335+ if ( operation . RequestBody is null )
336+ {
337+ operation . RequestBody = requestBody ;
338+ }
339+ else if ( requestBody is not null )
340+ {
341+ // Merge additional accepted content types that are defined by additional endpoint descriptions.
342+ var existingContent = operation . RequestBody . Content ;
343+ foreach ( var additionalContent in requestBody . Content )
344+ {
345+ if ( ! existingContent . ContainsKey ( additionalContent . Key ) )
346+ {
347+ existingContent . Add ( additionalContent ) ;
348+ }
349+ }
350+ }
351+ }
352+
337353 return operation ;
338354 }
339355
0 commit comments