From 340dc3a8f21c4f0c52684aedc83891f8cd294a0d Mon Sep 17 00:00:00 2001 From: Bo Bendtsen Date: Mon, 2 Oct 2023 15:54:56 +0200 Subject: [PATCH] Fix for multipart/formdata schema bug. (#4476) Fixes #3524 and #4392 --- .../BinaryTests.cs | 126 ++++++++++++++++++ .../Models/CSharpFileTemplateModel.cs | 2 +- .../Models/OperationModelBase.cs | 2 +- 3 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/NSwag.CodeGeneration.CSharp.Tests/BinaryTests.cs b/src/NSwag.CodeGeneration.CSharp.Tests/BinaryTests.cs index d11a84452a..1f5a83cc33 100644 --- a/src/NSwag.CodeGeneration.CSharp.Tests/BinaryTests.cs +++ b/src/NSwag.CodeGeneration.CSharp.Tests/BinaryTests.cs @@ -6,6 +6,7 @@ namespace NSwag.CodeGeneration.CSharp.Tests { public class BinaryTests { + [Fact] public async Task When_body_is_binary_then_stream_is_used_as_parameter_in_CSharp() { @@ -381,6 +382,131 @@ public async Task WhenSpecContainsFormDataInNestedMultipartForm_ThenFormDataIsUs Assert.Contains("class FileParameter", code); Assert.Contains("content_.Add(content_contents_, \"Contents\", contents.FileName ?? \"Contents\");", code); } + [Fact] + public async Task When_multipart_with_ref_should_read_schema() + { + var yaml = @"openapi: 3.0.0 +servers: + - url: https://www.example.com/ +info: + version: '2.0.0' + title: 'Test API' +paths: + /files: + post: + tags: + - Files + summary: 'Add File' + operationId: addFile + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAddFileResponse' + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/CreateAddFileRequest' +components: + schemas: + CreateAddFileResponse: + type: object + required: + - fileId + properties: + fileId: + type: string + format: uuid + CreateAddFileRequest: + type: object + additionalProperties: false + properties: + file: + type: string + format: binary + model: + type: string + enum: ['model-1'] + required: + - file + - model"; + + var document = await OpenApiYamlDocument.FromYamlAsync(yaml); + + // Act + var codeGenerator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings()); + var code = codeGenerator.GenerateFile(); + //// Assert + Assert.Contains("public virtual async System.Threading.Tasks.Task AddFileAsync(FileParameter file, Model? model, System.Threading.CancellationToken cancellationToken)", code); + Assert.Contains("var content_file_ = new System.Net.Http.StreamContent(file.Data);", code); + Assert.Contains("public partial class FileParameter", code); + } + [Fact] + public async Task When_multipart_inline_schema() + { + var yaml = @"openapi: 3.0.0 +servers: + - url: https://www.example.com/ +info: + version: '2.0.0' + title: 'Test API' +paths: + /files: + post: + tags: + - Files + summary: 'Add File' + operationId: addFile + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAddFileResponse' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + additionalProperties: false + properties: + file: + type: string + format: binary + model: + type: string + enum: ['model-1'] + required: + - file + - model +components: + schemas: + CreateAddFileResponse: + type: object + required: + - fileId + properties: + fileId: + type: string + format: uuid"; + + var document = await OpenApiYamlDocument.FromYamlAsync(yaml); + + // Act + var codeGenerator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings()); + var code = codeGenerator.GenerateFile(); + + //// Assert + Assert.Contains("public virtual async System.Threading.Tasks.Task AddFileAsync(FileParameter file, Model? model, System.Threading.CancellationToken cancellationToken)", code); + Assert.Contains("var content_file_ = new System.Net.Http.StreamContent(file.Data);", code); + Assert.Contains("public partial class FileParameter", code); + } } } diff --git a/src/NSwag.CodeGeneration.CSharp/Models/CSharpFileTemplateModel.cs b/src/NSwag.CodeGeneration.CSharp/Models/CSharpFileTemplateModel.cs index 751645bd7a..89458e284f 100644 --- a/src/NSwag.CodeGeneration.CSharp/Models/CSharpFileTemplateModel.cs +++ b/src/NSwag.CodeGeneration.CSharp/Models/CSharpFileTemplateModel.cs @@ -97,7 +97,7 @@ public CSharpFileTemplateModel( _settings.CSharpGeneratorSettings.ExcludedTypeNames?.Contains("FileParameter") != true && (_document.Operations.Any(o => o.Operation.ActualParameters.Any(p => p.ActualTypeSchema.IsBinary)) || _document.Operations.Any(o => o.Operation?.RequestBody?.Content?.Any(c => c.Value.Schema?.IsBinary == true || - c.Value.Schema?.ActualProperties.Any(p => p.Value.IsBinary || + c.Value.Schema?.ActualSchema.ActualProperties.Any(p => p.Value.IsBinary || p.Value.Item?.IsBinary == true || p.Value.Items.Any(i => i.IsBinary) ) == true) == true)); diff --git a/src/NSwag.CodeGeneration/Models/OperationModelBase.cs b/src/NSwag.CodeGeneration/Models/OperationModelBase.cs index 3f03e42625..c4a19eacac 100644 --- a/src/NSwag.CodeGeneration/Models/OperationModelBase.cs +++ b/src/NSwag.CodeGeneration/Models/OperationModelBase.cs @@ -348,7 +348,7 @@ protected IList GetActualParameters() var formDataSchema = _operation?.RequestBody?.Content?.ContainsKey("multipart/form-data") == true ? - _operation.RequestBody.Content["multipart/form-data"]?.Schema : null; + _operation.RequestBody.Content["multipart/form-data"]?.Schema.ActualSchema: null; if (formDataSchema != null && formDataSchema.ActualProperties.Count > 0) {