Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Execption thrown when generating OpenAPI document using F# #59536

Open
1 task done
josh-coproduct opened this issue Dec 18, 2024 · 0 comments
Open
1 task done

Execption thrown when generating OpenAPI document using F# #59536

josh-coproduct opened this issue Dec 18, 2024 · 0 comments
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-openapi

Comments

@josh-coproduct
Copy link

Is there an existing issue for this?

  • 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
open System
open System.Text.Json.Serialization
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Microsoft.AspNetCore.Http

[<JsonDerivedType(typeof<Dog>)>]
[<JsonDerivedType(typeof<Cat>)>]
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 }

[<EntryPoint>]
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<string>(fun () -> "Hello World!"))
    |> _.Produces<Test1Result>(StatusCodes.Status200OK, null, [||])
    |> ignore

    app.MapGet("/test2", Func<string>(fun () -> "Hello World!"))
    |> _.Produces<Animal>(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

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, 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.<<MapOpenApi>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>F56B68D2B55B5B7B373BA2E4796D897848BC0F04A969B1AF6260183E8B9E0BAF2__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass2_0.<<MapGet0>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

@martincostello martincostello added feature-openapi area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc labels Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-openapi
Projects
None yet
Development

No branches or pull requests

2 participants