RicoSuter / NSwag

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

Client code generation in NSwagStudio fails with NullReferenceException #2530

Open BlackGad opened 4 years ago

BlackGad commented 4 years ago

If specification contains response with defined content which has example but not have schema element code generation fails with an error

System.InvalidOperationException: Error while rendering Liquid template CSharp/Client.Class: 
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.

Runtime: NetCore20
   at NSwag.CodeGeneration.Models.OperationModelBase`2.get_UnwrappedResultType() in C:\projects\nswag\src\NSwag.CodeGeneration\Models\OperationModelBase.cs:line 120
   at NSwag.CodeGeneration.CSharp.Models.CSharpOperationModel.get_ResultType() in C:\projects\nswag\src\NSwag.CodeGeneration.CSharp\Models\CSharpOperationModel.cs:line 131
   --- End of inner exception stack trace ---
...

Here is sample of invalid configuration for studio

openapi: 3.0.1
info:
  description: >-
    Test API's
  version: 1.1.2
  title: Test API

paths:
  /testPath:
    get:
      operationId: testId
      description: "42"
      responses:
        '200':
          description: Returns some object
          content:
            application/json:
                example: {}

And here is valid configuration (with added schema property)

openapi: 3.0.1
info:
  description: >-
    Test API's
  version: 1.1.2
  title: Test API

paths:
  /testPath:
    get:
      operationId: testId
      description: "42"
      responses:
        '200':
          description: Returns some object
          content:
            application/json:
                schema:
                    type: object
                example: {}
ArtemAvramenko commented 2 years ago

Another stack trace:

System.NullReferenceException: Object reference not set to an instance of an object.
   at NSwag.CodeGeneration.CSharp.Models.CSharpOperationModel.ResolveParameterType(OpenApiParameter parameter) in C:\projects\nswag\src\NSwag.CodeGeneration.CSharp\Models\CSharpOperationModel.cs:line 272
   at NSwag.CodeGeneration.CSharp.Models.CSharpOperationModel.<>c__DisplayClass5_0.<.ctor>b__5(OpenApiParameter parameter) in C:\projects\nswag\src\NSwag.CodeGeneration.CSharp\Models\CSharpOperationModel.cs:line 76
   at System.Linq.Enumerable.SelectListIterator`2.ToList()
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at NSwag.CodeGeneration.CSharp.Models.CSharpOperationModel..ctor(OpenApiOperation operation, CSharpGeneratorBaseSettings settings, CSharpGeneratorBase generator, CSharpTypeResolver resolver) in C:\projects\nswag\src\NSwag.CodeGeneration.CSharp\Models\CSharpOperationModel.cs:line 74
   at NSwag.CodeGeneration.CSharp.CSharpClientGenerator.CreateOperationModel(OpenApiOperation operation, ClientGeneratorBaseSettings settings) in C:\projects\nswag\src\NSwag.CodeGeneration.CSharp\CSharpClientGenerator.cs:line 78
   at NSwag.CodeGeneration.ClientGeneratorBase`3.<>c__DisplayClass17_0.<GetOperations>b__1(<>f__AnonymousType0`3 tuple) in C:\projects\nswag\src\NSwag.CodeGeneration\ClientGeneratorBase.cs:line 239
   at System.Linq.Enumerable.SelectEnumerableIterator`2.ToList()
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at NSwag.CodeGeneration.ClientGeneratorBase`3.GetOperations(OpenApiDocument document) in C:\projects\nswag\src\NSwag.CodeGeneration\ClientGeneratorBase.cs:line 222
   at NSwag.CodeGeneration.ClientGeneratorBase`3.GenerateAllClientTypes() in C:\projects\nswag\src\NSwag.CodeGeneration\ClientGeneratorBase.cs:line 176
   at NSwag.CodeGeneration.ClientGeneratorBase`3.GenerateFile(ClientGeneratorOutputType outputType) in C:\projects\nswag\src\NSwag.CodeGeneration\ClientGeneratorBase.cs:line 80
   at NSwag.Commands.CodeGeneration.SwaggerToCSharpClientCommand.GenerateContracts(Dictionary`2 result, CSharpClientGenerator clientGenerator) in C:\projects\nswag\src\NSwag.Commands\Commands\CodeGeneration\OpenApiToCSharpClientCommand.cs:line 296
   at NSwag.Commands.CodeGeneration.SwaggerToCSharpClientCommand.<RunAsync>b__95_0() in C:\projects\nswag\src\NSwag.Commands\Commands\CodeGeneration\OpenApiToCSharpClientCommand.cs:line 267
   at NSwag.Commands.CodeGeneration.SwaggerToCSharpClientCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\CodeGeneration\OpenApiToCSharpClientCommand.cs:line 248
   at NSwag.Commands.NSwagDocument.ExecuteAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocument.cs:line 85
   at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 85
   at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 39
   at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input)
   at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input)
   at NConsole.CommandLineProcessor.Process(String[] args, Object input)
   at NSwag.Commands.NSwagCommandProcessor.Process(String[] args) in C:\projects\nswag\src\NSwag.Commands\NSwagCommandProcessor.cs:line 55child_process.js:836

Fails on that spec:

      parameters:
        - schema:
            type: array
          in: query
          name: bookId

Works with:

      parameters:
        - schema:
            type: array
            items:
              type: integer
          in: query
          name: bookId

It would be nice to do fallback to object in that cases.

rpbeukes commented 2 years ago

I also investigated this and

src/NSwag.CodeGeneration.CSharp/Models/CSharpOperationModel.cs

threw Object reference not set... because Item in schema.Item.IsBinary is null.

...
if (schema.Type == JsonObjectType.Array && schema.Item.IsBinary)
{
    return "System.Collections.Generic.IEnumerable<FileParameter>";
}
...

My suggestion to help it tick along.

...
if (schema.Type == JsonObjectType.Array && (schema.Item?.IsBinary ?? false))
{
    return "System.Collections.Generic.IEnumerable<FileParameter>";
}
...

I've tested it and the app does not blow up anymore - yes! It also passed all the tests, also yes!

I still have to test if the output generated will work properly, but I guess it would as the actual parameter which failed for me is generated like this: System.Collections.Generic.IEnumerable<object> status and what it should be is System.Collections.Generic.IEnumerable<string> status

System.Threading.Tasks.Task<SomeResponse> GetYourFavMethodAsync(int? start = null, System.Collections.Generic.IEnumerable<object> status = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));