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

[Bug]: Example value in XML comment doesn't work when using source generation for JSON serialization #2985

Closed
hackerzhuli opened this issue Jul 17, 2024 · 6 comments
Labels
aot Relates to native AoT support

Comments

@hackerzhuli
Copy link

hackerzhuli commented Jul 17, 2024

Describe the bug

Hello, I can't get example value in XML comment to work in Swagger with this library. My project is an Web API based on Asp.net Core, Native AOT, .net 8 and Minimal API. JSON serializaion is source generation based.

Example:

public record What(string Content);

public static class TestEndPoint
{
    /// <summary>
    /// This is swash
    /// </summary>
    /// <param name="name" example="my name">The name</param>
    /// <returns></returns>
    public static Ok<What> Swash(string name)
    {
        return TypedResults.Ok(new What("what"));
    } 
}

If I delete example="my name", swagger works, that is, XML comment is used, for example, summary "This is swash" is shown in Swagger page. With example="my name", opening the Swagger page throws an exception.

Expected behavior

Show an example value in corresponding Swagger endpoint parameter.

Actual behavior

Throws an exception when I open swagger url.

Steps to reproduce

reproduce repo: https://github.com/hackerzhuli/TestSwash

Exception(s) (if any)

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Failed to generate Operation for action - HTTP: GET /test/swash => Swash. See inner exception
       ---> System.InvalidOperationException: Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property.
         at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled()
         at System.Text.Json.JsonSerializerOptions.ConfigureForJsonSerializer()
         at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
         at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
         at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
         at Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsExampleHelper.Create(SchemaRepository schemaRepository, OpenApiSchema schema, String exampleString)
         at Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter.ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext context)
         at Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter.Apply(OpenApiParameter parameter, ParameterFilterContext context)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateParameter(ApiParameterDescription apiParameter, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.<>c__DisplayClass16_0.<GenerateParameters>b__1(ApiParameterDescription apiParam)
         at System.Linq.Enumerable.WhereSelectListIterator`2.ToList()
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateParameters(ApiDescription apiDescription, SchemaRepository schemaRespository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)

Swashbuckle.AspNetCore version

6.6.2

.NET Version

8.0.107

Anything else?

No response

@martincostello
Copy link
Collaborator

Looks like this was caused by #2727 which introduced the below line of code, which is not compatible with native AoT:

Swashbuckle.AspNetCore.SwaggerGen doesn't currently support native AoT and is not marked as trim compatible (unlike Swashbuckle.AspNetCore.SwaggerUI) (and I'm not sure it ever will due to the amount of work it would likely entail).

Fixing this specific line of code would need us to add a custom JsonSerializationContext with support for the string type, but there's no guarantee you won't hit some other limitation in the same area.

At the moment, any success with Swashbuckle in native AoT is an accident, rather than by design.

@martincostello martincostello added the aot Relates to native AoT support label Jul 17, 2024
@martincostello
Copy link
Collaborator

These are all the errors (26) I get locally if I mark the library as needing to be AoT compatible:

2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\DependencyInjection\SwaggerGenServiceCollectionExtensions.cs(86,24,86,53): error IL3050: Using member 'System.Text.Json.JsonSerializerOptions.Default.get' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(42,34,42,63): error IL3050: Using member 'System.Type.GetEnumValues()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues<T> or the GetEnumValuesAsUnderlyingType method instead.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(73,44,73,67): error IL3050: Using member 'System.Type.GetEnumValues()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues<T> or the GetEnumValuesAsUnderlyingType method instead.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\DependencyInjection\SwaggerGenServiceCollectionExtensions.cs(86,24,86,53): error IL2026: Using member 'System.Text.Json.JsonSerializerOptions.Default.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(106,20,106,77): error IL3050: Using member 'System.Text.Json.JsonSerializer.Serialize(Object, Type, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(106,20,106,77): error IL2026: Using member 'System.Text.Json.JsonSerializer.Serialize(Object, Type, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\MemberInfoExtensions.cs(25,60,25,100): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.PublicFields', 'DynamicallyAccessedMemberTypes.PublicNestedTypes', 'DynamicallyAccessedMemberTypes.PublicProperties', 'DynamicallyAccessedMemberTypes.PublicEvents' in call to 'System.Type.GetMember(String)'. The return value of method 'Microsoft.AspNetCore.Mvc.ModelMetadataTypeAttribute.MetadataType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\DependencyInjection\ConfigureSchemaGeneratorOptions.cs(50,20,50,122): error IL2072: 'instanceType' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider, Type, params Object[])'. The return value of method 'Swashbuckle.AspNetCore.SwaggerGen.FilterDescriptor.Type.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\DependencyInjection\ConfigureSwaggerGeneratorOptions.cs(84,20,84,122): error IL2072: 'instanceType' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider, Type, params Object[])'. The return value of method 'Swashbuckle.AspNetCore.SwaggerGen.FilterDescriptor.Type.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\SchemaGeneratorOptions.cs(57,20,57,48): error IL2026: Using member 'System.Reflection.Assembly.GetTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\TypeExtensions.cs(42,19,42,49): error IL2067: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The parameter 'type' of method 'Swashbuckle.AspNetCore.SwaggerGen.TypeExtensions.GetDefaultValue(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\TypeExtensions.cs(28,24,28,44): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'type' of method 'Swashbuckle.AspNetCore.SwaggerGen.TypeExtensions.IsConstructedFrom(Type, Type, out Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\TypeExtensions.cs(48,44,48,64): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'type' of method 'Swashbuckle.AspNetCore.SwaggerGen.TypeExtensions.GetInheritanceChain(Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SwaggerGenerator\ApiParameterDescriptionExtensions.cs(76,19,76,86): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperty(String)'. The return value of method 'Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata.ContainerType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\SchemaGenerator.cs(292,38,292,69): error IL3050: Using member 'System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\SchemaGenerator.cs(303,31,303,74): error IL3050: Using member 'System.Type.GetEnumValues()' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use Enum.GetValues<T> or the GetEnumValuesAsUnderlyingType method instead.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\SchemaGenerator.cs(292,38,292,69): error IL2026: Using member 'System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\XmlComments\XmlCommentsExampleHelper.cs(19,23,19,62): error IL3050: Using member 'System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\XmlComments\XmlCommentsExampleHelper.cs(19,23,19,62): error IL2026: Using member 'System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\XmlComments\MethodInfoExtensions.cs(14,36,14,70): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'. The return value of method 'System.Type.GetGenericTypeDefinition()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SwaggerGenerator\OpenApiAnyFactory.cs(12,35,12,80): error IL3050: Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SwaggerGenerator\OpenApiAnyFactory.cs(12,35,12,80): error IL2026: Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(162,47,162,73): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'objectType' of method 'Swashbuckle.AspNetCore.SwaggerGen.JsonSerializerDataContractResolver.GetDataPropertiesFor(Type, out Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(163,19,163,62): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties', 'DynamicallyAccessedMemberTypes.NonPublicProperties' in call to 'System.Type.GetProperties(BindingFlags)'. The parameter 'objectType' of method 'Swashbuckle.AspNetCore.SwaggerGen.JsonSerializerDataContractResolver.GetDataPropertiesFor(Type, out Type)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(214,77,214,95): error IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'System.Type.GetConstructors()'. The return value of method 'System.Reflection.MemberInfo.DeclaringType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
2>C:\Coding\domaindrivendev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.SwaggerGen\SchemaGenerator\JsonSerializerDataContractResolver.cs(162,91,162,125): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties', 'DynamicallyAccessedMemberTypes.NonPublicProperties' in call to 'System.Type.GetProperties(BindingFlags)'. The parameter 'i' of method 'lambda expression' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.

Some of them can be trivially fixed (will try a PR shortly), but some of them might be too much effort to invest in fixing when the new OpenAPI support in ASP.NET Core 9 will support native AoT out of the box for people who care about such a use case: dotnet/aspnetcore#56023

martincostello added a commit to martincostello/Swashbuckle.AspNetCore that referenced this issue Jul 17, 2024
Use the JSON source generator with `net8.0` to make XML comments generation compatible with native AoT.

Relates to domaindrivendev#2985.
@martincostello
Copy link
Collaborator

Taking a look at the warnings, only two of these look like they can be resolved - the rest would require significant refactoring as Swashbuckle is so heavily based on runtime reflection.

I would have thought you will have received multiple warnings from the trimmer when you published your application before even trying to run it.

Can you try out #2986 from source and see if it resolves your issue? If it does I'll be inclined to have it merged as it unblocks you, but if you just run into a different problem that it's probably not worth pursuing further.

@hackerzhuli
Copy link
Author

Hello, thank you very much. Actually I am not in a hurry at all. Having examples in swagger is not required for my project right now at all(It'll be nice, though). I guess I'll just wait for aot support.

@martincostello
Copy link
Collaborator

Would you like to try the fix out? Otherwise I don't have an easy way to validate the fix I just pushed.

@martincostello
Copy link
Collaborator

Closing as we don't intend to make SwaggerGen AoT compatible.

@martincostello martincostello closed this as not planned Won't fix, can't repro, duplicate, stale Jul 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
aot Relates to native AoT support
Projects
None yet
Development

No branches or pull requests

2 participants