-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
With the recent decision to deprecate the OpenAPI/API Convention analyzers in .NET 10 in favor of TypedResults and XML comments, there are several developer experience (DX) regressions when working with Controllers.
While TypedResults and Results<T1, T2> work (almost) seamlessly for Minimal APIs, applying this pattern to Controllers introduces significant boilerplate, breaks existing automation (like ProblemDetails generation), introduces issues with OpenAPI support and creates friction with the C# type system that didn't exist with the previous ProducesResponseType attribute-based approach.
This issue explains my worries and thoughts. I am looking for feedback from the team/community. Does the team/community understand or share my worries? If not, I'd love to know why!
Personally, I believe it is too early to deprecate OpenAPI Analyzer and I would love to to see it de-deprecated until the issues are fixed. However, this might go too far, so again, I am curious for the thoughts from the team!
Original Controller Approach
[HttpGet("original")]
[ProducesResponseType<IReadOnlyCollection<WeatherForecast>>(StatusCodes.Status200OK, Description = "OK")]
[ProducesResponseType(StatusCodes.Status400BadRequest, Description = "Bad Request")]
[ProducesResponseType(StatusCodes.Status409Conflict, Description = "Conflict")]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Description = "Unprocessable")]
public IActionResult GetOriginal()
{
if (DateTime.Now.Day == 3)
return Conflict();
if (DateTime.Now.Day == 4)
return BadRequest();
if (DateTime.Now.Day == 5)
return UnprocessableEntity();
return Ok(Array.Empty<WeatherForecast>());
}Pros:
- Automatic OpenAPI metadata via attributes
- Warnings when a a response code was added that wasn't annotated with
ProducesResponseType - Automatic ProblemDetails for errors
- No explicit casting required
- It's usually a good idea to return interface types from methods, so that's why you often see
IEnumerable/IReadOnlyCollectionbeing returned.
- It's usually a good idea to return interface types from methods, so that's why you often see
New TypedResults + XML comments approach
/// <response code="200">OK</response>
/// <response code="400">Bad Request</response>
/// <response code="409">Conflict</response>
/// <response code="422">Unprocessable</response>
[HttpGet("typedresults")]
public Results<Ok<IReadOnlyCollection<WeatherForecast>>, ProblemHttpResult, ValidationProblem> Get()
{
if (DateTime.Now.Day == 3)
return TypedResults.Problem(statusCode: StatusCodes.Status409Conflict);
if (DateTime.Now.Day == 4)
return TypedResults.ValidationProblem(new Dictionary<string, string[]>());
if (DateTime.Now.Day == 5)
return TypedResults.Problem(statusCode: StatusCodes.Status422UnprocessableEntity);
var list = Array.Empty<WeatherForecast>();
IReadOnlyCollection<WeatherForecast> readOnlyList = list;
return TypedResults.Ok(readOnlyList); // Explicit cast required
}Challenges:
- Explicit casting required: cannot directly return a List or array.
- ProblemDetails must be created manually, losing trace IDs if not handled.
- Returning TypedResults.SPECIFICMETHOD does not include a ProblemDetails body, losing consistency.
- The alternative is to return
TypedResults.Problem, but this is not added to the OpenAPI document! - OpenAPI metadata for the response description relies on XML comments rather than attributes, reducing editor support and discoverability.
Even though this gives us compile time validation of the types returned, having to explicitly cast for interface compatibility is a pain. It also doesn't validate if a type is returned that isn't part of the Results<> type list declaration.
Suggestions/Requests
- Consider improving the controller experience with TypedResults to preserve:
- Automatic ProblemDetails including trace IDs
- Compile-time safety for multiple error types
- Full OpenAPI metadata with per-response descriptions
- Provide clear guidance and examples for combining TypedResults + XML comments for multi-error responses in controller APIs.
- Reduce friction in returning common collection types without explicit casts.
- Add support for TypedResults.Problem in the OpenAPI document