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][aspnetcore] FileParameters should be refactor to multimap and support content-type #11132

Open
5 of 6 tasks
joaocmendes opened this issue Dec 15, 2021 · 4 comments
Open
5 of 6 tasks

Comments

@joaocmendes
Copy link
Contributor

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

Build fails for a request with multipart-form-data when there is multiple files for the same field.
The client receives a List but this can't be handled by RequestOptions because it only accepts a single file for the same key.

The API consumed requires the content-type for the file sent (e.g. application/pdf, image/png).
There is no way to achieve this with the actual generator.

openapi-generator version

openapi-generator-cli-5.3.0.jar

OpenAPI declaration file content or url
{
  "openapi": "3.0.1",
  "info": {
    "title": "Test API",
    "version": "1.0"
  },
  "servers": [
    {
      "url": "/ocrapis"
    }
  ],
  "paths": {
    "/api/v1/Documents/{entityName}": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Returns Extraction Result of Your Request",
        "parameters": [
          {
            "name": "entityName",
            "in": "path",
            "description": "Tenant Name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "UploadedFiles": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    },
                    "description": "Files to be Extracted"
                  },
                  "UploadedFileTypes": {
                    "type": "string",
                    "description": "File Type"
                  },
                  "ProjectName": {
                    "type": "string",
                    "description": "Project Name of Tenant"
                  }
                }
              },
              "encoding": {
                "UploadedFiles": {
                  "style": "form",
				          "contentType": "application/pdf"
                },
                "UploadedFileTypes": {
                  "style": "form"
                },
                "ProjectName": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successfull Request",
            "content": {
              "application/json": {
                "schema": {
                "type": "object"	
                }
              }
            }
          }
        }
      }
    },
  }
}
Generation Details

java -jar openapi-generator-cli-5.3.0.jar generate -i swagger.json -g csharp-netcore -o testNew

Steps to reproduce

generate the code
build the code
it fails with Error CS1503 Argument 2: cannot convert from 'System.Collections.Generic.List<System.IO.Stream>' to 'System.IO.Stream'

Suggest a fix

Change on RequestOptions class the field FileParameters from Dictionary<string, Stream> to Multimap<string, Stream> would fix the issue as follows:

// Actual 
public Dictionary<string, Stream> FileParameters { get; set; }

// New 
public Multimap<string, Stream> FileParameters { get; set; }

This fix also requires a change at ApiClient to iterate the multiples files under the same key.
Code block:
image

FileParameters should support the defintion of a ContentType or the code could infer from the file extension (but it can be tricky not for the common types like pdf but for some ambiguous types).
It's already supported by aspnetcore httpClient and RestSharp when creating file as follows:

public static FileParameter Create(string name, byte[] data, string filename, string contentType);
@saarivirtajCGI
Copy link

I tried out the fix, in addition to the above Multimap<string, Stream> RequestOptions class fix I applied the following fix to ApiClient, which seemed to do the trick:

if (options.FileParameters != null)
{
	foreach (var fileParam in options.FileParameters)
	{
		foreach(var item in fileParam.Value)
		{
			var bytes = ClientUtils.ReadAsBytes(item);
			var fileStream = item as FileStream;
			if (fileStream != null)
				request.Files.Add(FileParameter.Create(fileParam.Key, bytes, System.IO.Path.GetFileName(fileStream.Name)));
			else
				request.Files.Add(FileParameter.Create(fileParam.Key, bytes, "no_file_name_provided"));
		}
	}
}

@wing328
Copy link
Member

wing328 commented Jan 4, 2022

Please submit a PR with the suggested fix and we'll review accordingly.

@joaocmendes
Copy link
Contributor Author

@saarivirtajCGI In my opinion thats it, is the same code I had on on my side to make the workaround.
I haven't the time to go to the pre-generated code and check what we had to do in order to generate with this.

One not so simple is about the contentType. I've created an util method to get the content-type of the file based on the name but its not safe at all.
It's possible to create a class that extends FileStream and has an extra property to achieve this?

My code is the following:

    if (options.FileParameters != null)
    {
        foreach (var fileParam in options.FileParameters)
        {
            foreach (var file in fileParam.Value)
            {
                var bytes = ClientUtils.ReadAsBytes(file);
                var fileStream = file as FileStream;
                if (fileStream != null)
                    request.Files.Add(FileParameter.Create(fileParam.Key, bytes, System.IO.Path.GetFileName(fileStream.Name), this.GetContentTypeForFile(fileStream.Name)));
                else
                    request.Files.Add(FileParameter.Create(fileParam.Key, bytes, "no_file_name_provided"));
            }
        }
    }

joaocmendes added a commit to joaocmendes/openapi-generator that referenced this issue Jan 8, 2022
…Tools#11132)

Make FileParamerts a Multimap to enable sending more than one file with the same key.
@joaocmendes
Copy link
Contributor Author

@wing328 PR submited

wing328 pushed a commit that referenced this issue Jan 11, 2022
…#11259)

* [BUG][csharp-netcore] Fix Multi Files for the some FormField  (#11132)

Make FileParamerts a Multimap to enable sending more than one file with the same key.

* update documentation for csharp-netcore
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants
@wing328 @joaocmendes @saarivirtajCGI and others