Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
OpenApi v3.0 and later can describe multiple response "contents" for a single status code differentiated by the response content-type. Each "contents" definition can have its own schema. A common case may be:
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int32
title:
type: string
content:
type: string
text/html:
schema:
type: string
Currently this response description can't be created just using Produces
because each produces can specify only one response type (schema), so two Produces
are needed for the case above, but the second Produces
for a given status code overrides the information of the first, even if it is for a distinct content type.
Implementation Plan For Copilot
We need to add support for multiple response types with the same status code in ApiExplorer. This limitation currently exists because our ApiResponseTypeProvider only maintains a list of types based on status code. When two attributes specify the same code, the second entry overrides the first. This happens in ApiResponseTypeProvider.ReadResponseMetadata
. We need to update the code to support deduplicating based on status-code and content-type.
The relevant files are:
File | Purpose |
---|---|
ApiResponseTypeProvider.cs |
Change collection semantics and add helper record |
ApiResponseMetadataProviderContext.cs |
XML-doc only, note new behaviour |
ApiResponseTypeProviderTest.cs |
Regression tests for duplicate-status scenarios |
(No public APIs change; everything modified is internal to Mvc.ApiExplorer.) |
We should solve this by completing the following steps:
-
Add a compound key record
private readonly record struct ResponseKey( int StatusCode, Type? DeclaredType, string? ContentType);
-
Replace the status-code dictionary in ApiResponseTypeProvider
- var results = new Dictionary<int, ApiResponseType>(); + var results = new Dictionary<ResponseKey, ApiResponseType>();
-
Build a key for every discovered response
var key = new ResponseKey( apiResponseType.StatusCode, apiResponseType.Type, // may be null apiResponseType.ContentTypes.FirstOrDefault() // may be null ); results.TryAdd(key, apiResponseType); // preserves duplicates
Optional: if true duplicates arise (same code + type + content type) you may merge their
ContentTypes
collections instead of discarding either. -
Populate
SupportedResponseTypes
action.SupportedResponseTypes = results.Values.ToList();
-
(Nice-to-have) deterministic ordering
action.SupportedResponseTypes = results.Values .OrderBy(r => r.StatusCode) .ThenBy(r => r.Type?.Name) .ThenBy(r => r.ContentTypes.FirstOrDefault()) .ToList();
-
Unit tests
- Two
[ProducesResponseType]
attributes with identical status code but distinct content-types types ➜ assertSupportedResponseTypes.Count == 2
. - Verify ordering and
ContentTypes
merging logic if implemented. - Verify that multiple
Produces
calls on minimal API with identical status codes and different content-types produces multiple responses. - Verify that the Microsoft.AspNetCore.OpenApi generator produces the correct OpenAPI document for each scenario.
- Two