dotnet / dotnet/aspnetcore

Execption thrown when generating OpenAPI document using F#

Open
#59,536 0 comments 0 reactions 0 assignees View on GitHub
area-minimal feature-openapi
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 5h
Merged PRs (30d)
276

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

When using a very specific combination of types in F#, the OpenAPI document fails to generate and an exception is thrown. I believe it is a similar bug to #58213, but in this case the parent type is not referenced from a sub-type, which was the suspected cause in that case. Recreating the same code in C# failed to recreate the bug.

Specifically, all of these conditions have to be true to trigger the exception:

- `Dog.favoriteFoods` has to be an array, or at least not just a string
- `Test1Result` has to include fields of type `Dog` and `Animal`
- Both `Animal` and `Test1Result` have to be response types

```fsharp
open System
open System.Text.Json.Serialization
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Microsoft.AspNetCore.Http

[)>]
[)>]
type Animal() =
member val name = "" with get, set

and Cat() =
inherit Animal()
member val favoriteFood: string = "tuna" with get, set

and Dog() =
inherit Animal()
member val favoriteFoods: string[] = [||] with get, set

type Test1Result = { dog: Dog; animal: Animal }

[]
let main args =

let builder = WebApplication.CreateBuilder(args)

builder.Services.AddOpenApi() |> ignore

let app = builder.Build()

if app.Environment.IsDevelopment() then
app.MapOpenApi() |> ignore

app.MapGet("/test1", Func(fun () -> "Hello World!"))
|> _.Produces(StatusCodes.Status200OK, null, [||])
|> ignore

app.MapGet("/test2", Func(fun () -> "Hello World!"))
|> _.Produces(StatusCodes.Status200OK, null, [||])
|> ignore

app.Run()

0
```

### Expected Behavior

The OpenAPI document is successfully generated.

### Steps To Reproduce

A minimalist project recreating the issue is here:

[https://github.com/josh-coproduct/FSharp-OpenAPI-Bug-Sample](https://github.com/josh-coproduct/FSharp-OpenAPI-Bug-Sample)

It includes the F# code the triggers the bug, and the C# code that does not.

Launching the F# project should open a browser window to [http://localhost:5047/openapi/v1.json](http://localhost:5047/openapi/v1.json), which should trigger the bug and show the exception.

### Exceptions (if any)

```
System.ArgumentException: An item with the same key has already been added. Key: AnimalDog
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at Microsoft.AspNetCore.OpenApi.OpenApiSchemaReferenceTransformer.TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.ApplyTransformersAsync(OpenApiDocument document, IServiceProvider scopedServiceProvider, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(IServiceProvider scopedServiceProvider, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(IServiceProvider scopedServiceProvider, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions.<>c__DisplayClass0_0.<b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Http.Generated.F56B68D2B55B5B7B373BA2E4796D897848BC0F04A969B1AF6260183E8B9E0BAF2__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass2_0.<g__RequestHandler|5>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
```

### .NET Version

9.0.101

### Anything else?

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.