RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.61k stars 1.22k forks source link

help wanted: debugging exception inside NSwag 14 #4842

Open vvdb-architecture opened 3 months ago

vvdb-architecture commented 3 months ago

Hello,

I am trying to track down a problem when upgrading from NSwag 13 to NSwag 14. The error message I'm getting during the generation of the CSharp client using the post-build event:

  <Target Name="NSwag" AfterTargets="PostBuildEvent" Condition=" '$(Configuration)' == 'Debug' ">
    <Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development;NSwag=true" Command="$(NSwagExe_Net60) run ..\Sdks\controllers.nswag  /variables:Configuration=$(Configuration)" />
  </Target>

is the following:

15>System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
15> ---> System.InvalidOperationException: This operation is only valid on generic types.
15>   at System.RuntimeType.GetGenericTypeDefinition()
15>   at Namotion.Reflection.ContextualType.<get_Fields>b__36_0(FieldInfo field)
15>   at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
15>   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
15>   at Namotion.Reflection.ContextualType.get_Fields()
15>   at NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.ReflectionServiceBase`1.NJsonSchema.Generation.IReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, JsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateInheritance(ContextualType type, JsonSchema schema, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](Type type, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate(Type type, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateInheritance(ContextualType type, JsonSchema schema, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](Type type, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate(Type type, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateInheritance(ContextualType type, JsonSchema schema, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](Type type, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate(Type type, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateArray[TSchemaType](TSchemaType schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.AddProperty(JsonSchema parentSchema, ContextualAccessorInfo property, JsonTypeDescription propertyTypeDescription, String propertyName, Attribute requiredAttribute, Boolean hasRequiredAttribute, Boolean isNullable, Object defaultValue, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonReflectionService.LoadPropertyOrField(JsonProperty jsonProperty, ContextualAccessorInfo accessorInfo, Type parentType, JsonSchema parentSchema, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.ReflectionServiceBase`1.NJsonSchema.Generation.IReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, JsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateInheritance(ContextualType type, JsonSchema schema, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](Type type, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate(Type type, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateDictionaryValueSchema[TSchema](JsonSchemaResolver schemaResolver, ContextualType valueType)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateDictionary[TSchemaType](TSchemaType schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.AddProperty(JsonSchema parentSchema, ContextualAccessorInfo property, JsonTypeDescription propertyTypeDescription, String propertyName, Attribute requiredAttribute, Boolean hasRequiredAttribute, Boolean isNullable, Object defaultValue, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonReflectionService.LoadPropertyOrField(JsonProperty jsonProperty, ContextualAccessorInfo accessorInfo, Type parentType, JsonSchema parentSchema, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.ReflectionServiceBase`1.NJsonSchema.Generation.IReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, JsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateObject(JsonSchema schema, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](TSchemaType schema, ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.Generate[TSchemaType](ContextualType contextualType, JsonSchemaResolver schemaResolver)
15>   at NJsonSchema.Generation.JsonSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NSwag.Generation.OpenApiSchemaGenerator.GenerateWithReferenceAndNullability[TSchemaType](ContextualType contextualType, Boolean isNullable, JsonSchemaResolver schemaResolver, Action`2 transformation)
15>   at NSwag.Generation.AspNetCore.Processors.OperationResponseProcessor.Process(OperationProcessorContext operationProcessorContext)
15>   at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.RunOperationProcessors(OpenApiDocument document, ApiDescription apiDescription, Type controllerType, MethodInfo methodInfo, OpenApiOperationDescription operationDescription, List`1 allOperations, OpenApiDocumentGenerator generator, OpenApiSchemaResolver schemaResolver)
15>   at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.AddOperationDescriptionsToDocument(OpenApiDocument document, Type controllerType, List`1 operations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver)
15>   at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.GenerateApiGroups(OpenApiDocumentGenerator generator, OpenApiDocument document, IGrouping`2[] apiGroups, OpenApiSchemaResolver schemaResolver)
15>   at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.GenerateAsync(ApiDescriptionGroupCollection apiDescriptionGroups)
15>   at NSwag.Commands.Generation.AspNetCore.AspNetCoreToOpenApiCommand.GenerateDocumentWithDocumentProviderAsync(IServiceProvider serviceProvider) in /_/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs:line 245
15>   at NSwag.Commands.Generation.AspNetCore.AspNetCoreToOpenApiCommand.GenerateDocumentAsync(IServiceProvider serviceProvider, String currentWorkingDirectory) in /_/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs:line 239
15>   at NSwag.Commands.Generation.AspNetCore.AspNetCoreToOpenApiGeneratorCommandEntryPoint.Process(String commandContent, String outputFile, String applicationName) in /_/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiGeneratorCommandEntryPoint.cs:line 29
15>   --- End of inner exception stack trace ---
15>   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
15>   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
15>   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
15>   at NSwag.AspNetCore.Launcher.Program.Main(String[] args) in /_/src/NSwag.AspNetCore.Launcher/Program.cs:line 132
15>System.InvalidOperationException: Swagger generation failed with non-zero exit code '1'.
15>   at NSwag.Commands.Generation.AspNetCore.AspNetCoreToOpenApiCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in /_/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs:line 195
15>   at NSwag.Commands.NSwagDocumentBase.GenerateSwaggerDocumentAsync() in /_/src/NSwag.Commands/NSwagDocumentBase.cs:line 270
15>   at NSwag.Commands.NSwagDocument.ExecuteAsync() in /_/src/NSwag.Commands/NSwagDocument.cs:line 67
15>   at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in /_/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs:line 76
15>   at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in /_/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs:line 33
15>   at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input)
15>   at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input)
15>   at NSwag.Commands.NSwagCommandProcessor.ProcessAsync(String[] args) in /_/src/NSwag.Commands/NSwagCommandProcessor.cs:line 65

Now, I would love to know what type is causing the GetGenericTypeDefinition() to trip up and throw an exception. This worked perfectly with NSwag 13.

For this, I first implemented a processor that narrows down the method on the controller:

public class ControllerFilterProcessor : IOperationProcessor
{
    public bool Process(OperationProcessorContext context)
    {
        Console.WriteLine("[NSWAG] CONTROLLER " + context.ControllerType.Name + " " + context.MethodInfo.Name);
        return true;
    }
}

This is added as follows:

        option.OperationProcessors.Insert(0, new ControllerFilterProcessor());

Sadly, a close inspection did not reveal anything that narrowed down the problem. In fact, before the offending controller is reached, a lot of other controllers and methods with generic types are handled without issue.

Next, I defined a schema processor:

class SchemaProc : ISchemaProcessor
{
    public void Process(SchemaProcessorContext context)
    {
        Console.WriteLine("[NSWAG] SCHEMA " + context.ContextualType.ToString());
    }
}

... which I then injected using:

        option.SchemaSettings.SchemaProcessors.Add(new SchemaProc());

This did not tell me more. Just before the exception occurs, it writes:

15>[NSWAG] SCHEMA Guid: NotNullable

I don't see the connection between a Guid and a a generic type. And in the type being handled, a Guid doesn't even occur.

I noticed in the above stack trace that one of the methods is:

15>   at Namotion.Reflection.ContextualType.get_Fields()

... so I changed the SchemaProc implementation as follows:

class SchemaProc : ISchemaProcessor
{
    public void Process(SchemaProcessorContext context)
    {
        Console.WriteLine("[NSWAG] SCHEMA " + context.ContextualType.ToString());
        try
        {
            var fields = context.ContextualType.Fields.ToArray();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error while getting fields: " + ex.Message);
        }
    }
}

The reasoning is that by calling the method that occurs in the stack trace myself, I could trigger the exception and investigate from there. Sadly, that didn't work: the body of the above catch is never executed.

The only rational explanation is that the exception is thrown before SchemaProc.Process is being called.

This makes me throw my hands up in the air and ask for help on this forum. What else is there to do? The controllers and their return types are very complicated, and systematically removing types "until it works" will take more time than I have. Is there some kind of trace flag I can set to have more detailed information?

danchristensen2000 commented 3 months ago

I have also run into this same error after upgrading from 13.20.0 to 14.0.7, and am stuck. I have no idea where the error is occurring.

adam-clauss commented 3 weeks ago

@vvdb-architecture / @danchristensen2000 - I don't know if you are still trying to solve this, but we ran into what appears to be a very similar error that I noted here https://github.com/RicoSuter/NSwag/issues/4918

We were able to track down the trigger by running our web api in the debugger with it set to stop on all exceptions. Launch a browser to the swagger.json URL. This caused it to stop in the debugger at that location. By looking at what variables we could see in the debugger (particularly in Namotion.Reflection.ContextualType.Fields.get(), the base.Type pointed directly to the Action type in question), we were able to get a clue as to where this was coming from.

As with you, this issue began appearing after updating from nswag v13 to v14.