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

NSwag C# DTO generation fails on object arrays with the characters " - " #4863

Open tsemer opened 2 months ago

tsemer commented 2 months ago

We've recently encountered the following exception when trying to generate C# DTOs from a large schema:

System.InvalidOperationException: Error while rendering Liquid template CSharp/Class: 
Index was outside the bounds of the array.
Full stack trace: (click to expand) System.InvalidOperationException: Error while rendering Liquid template CSharp/Class: Index was outside the bounds of the array. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array. Runtime: Net80 at NJsonSchema.ConversionUtilities.ConvertToUpperCamelCase(String input, Boolean firstCharacterMustBeAlpha) at NJsonSchema.DefaultTypeNameGenerator.Generate(JsonSchema schema, String typeNameHint) at NJsonSchema.DefaultTypeNameGenerator.<>c__DisplayClass8_0.b__0(String p) at System.Linq.Enumerable.SelectArrayIterator`2.MoveNext() at System.String.Join(String separator, IEnumerable`1 values) at NJsonSchema.DefaultTypeNameGenerator.Generate(JsonSchema schema, String typeNameHint, IEnumerable`1 reservedTypeNames) at NJsonSchema.CodeGeneration.TypeResolverBase.GetOrGenerateTypeName(JsonSchema schema, String typeNameHint) at NJsonSchema.CodeGeneration.CSharp.CSharpTypeResolver.Resolve(JsonSchema schema, Boolean isNullable, String typeNameHint, Boolean checkForExistingSchema) at NJsonSchema.CodeGeneration.CSharp.CSharpTypeResolver.Resolve(JsonSchema schema, Boolean isNullable, String typeNameHint) at NJsonSchema.CodeGeneration.CSharp.CSharpTypeResolver.ResolveArrayOrTuple(JsonSchema schema) at NJsonSchema.CodeGeneration.CSharp.CSharpTypeResolver.Resolve(JsonSchema schema, Boolean isNullable, String typeNameHint, Boolean checkForExistingSchema) at NJsonSchema.CodeGeneration.CSharp.CSharpTypeResolver.Resolve(JsonSchema schema, Boolean isNullable, String typeNameHint) at NJsonSchema.CodeGeneration.CSharp.Models.PropertyModel.get_Type() at Fluid.Accessors.PropertyInfoAccessor.Invoker`2.Invoke(Object target) at Fluid.Accessors.PropertyInfoAccessor.Get(Object obj, String name, TemplateContext ctx) at Fluid.Values.ObjectValueBase.GetValueAsync(String name, TemplateContext context) at Fluid.Ast.IdentifierSegment.ResolveAsync(FluidValue value, TemplateContext context) at Fluid.Ast.MemberExpression.EvaluateAsync(TemplateContext context) at Fluid.Ast.OutputStatement.WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) at Fluid.Ast.ForStatement.WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) at Fluid.Parser.FluidTemplate.Awaited(ValueTask`1 task, TextWriter writer, TextEncoder encoder, TemplateContext context, IReadOnlyList`1 statements, Int32 startIndex) at Fluid.FluidTemplateExtensions.RenderAsync(IFluidTemplate template, TemplateContext context, TextEncoder encoder, Boolean isolateContext) at NJsonSchema.CodeGeneration.DefaultTemplateFactory.LiquidTemplate.Render() --- End of inner exception stack trace --- at NJsonSchema.CodeGeneration.DefaultTemplateFactory.LiquidTemplate.Render() at NJsonSchema.CodeGeneration.CodeArtifact..ctor(String typeName, String baseTypeName, CodeArtifactType type, CodeArtifactLanguage language, CodeArtifactCategory category, ITemplate template) at NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.GenerateClass(JsonSchema schema, String typeName) at NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.GenerateType(JsonSchema schema, String typeNameHint) at NJsonSchema.CodeGeneration.GeneratorBase.GenerateTypes() at NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.GenerateTypes() at NSwag.CodeGeneration.CSharp.CSharpGeneratorBase.GenerateDtoTypes() in /_/src/NSwag.CodeGeneration.CSharp/CSharpGeneratorBase.cs:line 106 at NSwag.CodeGeneration.ClientGeneratorBase`3.GenerateFile(ClientGeneratorOutputType outputType) in /_/src/NSwag.CodeGeneration/ClientGeneratorBase.cs:line 75 at NSwag.CodeGeneration.ClientGeneratorBase`3.GenerateFile() in /_/src/NSwag.CodeGeneration/ClientGeneratorBase.cs:line 65 at NSwag.Commands.CodeGeneration.OpenApiToCSharpControllerCommand.RunAsync() in /_/src/NSwag.Commands/Commands/CodeGeneration/OpenApiToCSharpControllerCommand.cs:line 93 at NSwag.Commands.CodeGeneration.OpenApiToCSharpControllerCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in /_/src/NSwag.Commands/Commands/CodeGeneration/OpenApiToCSharpControllerCommand.cs:line 84 at NSwag.Commands.NSwagDocument.<>c__DisplayClass4_1.<b__0>d.MoveNext() in /_/src/NSwag.Commands/NSwagDocument.cs:line 81 --- End of stack trace from previous location --- at NSwag.Commands.NSwagDocument.ExecuteAsync() in /_/src/NSwag.Commands/NSwagDocument.cs:line 86 at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in /_/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs:line 76 at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in /_/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs:line 33 at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input) at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input) at NSwag.Commands.NSwagCommandProcessor.ProcessAsync(String[] args) in /_/src/NSwag.Commands/NSwagCommandProcessor.cs:line 65

The source schema seems to be valid. I've managed to isolate the root cause to be very specific: Object arrays with the characters - (space dash space). I've created a minimal repro to help speed up resolution:

openapi: 3.1.0
info:
  title: Minimal Repro Array Bug - OpenAPI 3.0
  version: 1.0.0
paths:
  /bestpet:
    get:
      tags:
        - pet
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                  previous - owners:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string

Removing any of the three characters - from previous - owners makes generation succeed.

Confirmed affected platforms / versions:

I've tried any configuration parameter I could find including all runtime versions, all class styles and both JSON libraries. All seem to produce this exception.

I'll also add that TS client generation succeeds.

If I can provide any additional info about the running environment please let me know.