swagger-api / swagger-codegen

swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
http://swagger.io
Apache License 2.0
16.94k stars 6.03k forks source link

ASP.Net Core File badly handled in csharp-dotnet2 client #9723

Open BLS-Z340 opened 5 years ago

BLS-Z340 commented 5 years ago
Description

Code for downloading files generated by swagger-codegen (csharp) is wrong. It may work in most cases, but it cuts my .zip file after \0.

Code generated with swagger-codegen:

        public System.IO.Stream GetVersionFile (int? versionId)
        {
            // verify the required parameter 'versionId' is set
            if (versionId == null) throw new ApiException(400, "Missing required parameter 'versionId' when calling GetVersionFile");

            var path = "/api/Versions/{versionId}/File";
            path = path.Replace("{format}", "json");
            path = path.Replace("{" + "versionId" + "}", ApiClient.ParameterToString(versionId));

            var queryParams = new Dictionary<String, String>();
            var headerParams = new Dictionary<String, String>();
            var formParams = new Dictionary<String, String>();
            var fileParams = new Dictionary<String, FileParameter>();
            String postBody = null;

            // authentication setting, if any
            String[] authSettings = new String[] { "Bearer" };

            // make the HTTP request
            IRestResponse response = (IRestResponse) ApiClient.CallApi(path, Method.GET, queryParams, postBody, headerParams, formParams, fileParams, authSettings);

            if (((int)response.StatusCode) >= 400)
                throw new ApiException ((int)response.StatusCode, "Error calling GetVersionFile: " + response.Content, response.Content);
            else if (((int)response.StatusCode) == 0)
                throw new ApiException ((int)response.StatusCode, "Error calling GetVersionFile: " + response.ErrorMessage, response.ErrorMessage);

            return (System.IO.Stream) ApiClient.Deserialize(response.Content, typeof(System.IO.Stream), response.Headers);
        }

response.Length has bigger value than response.Content.Length because there is a \0 in my .zip file. Then the response.Content is passed to File.WriteAllText. There is no length specified so my file is smaller than it is supposed to be. It's a easy fix in generated code, but it's a huge waste of time to do this every time after generating the client code.

Swagger-codegen version

swagger-codegen-cli-3.0.11

Swagger declaration file content or url

(for YAML code) or

...
            "get": {
                "tags": [ "Applications" ],
                "summary": "Version file download",
                "operationId": "GetVersionFile",
                "consumes": [],
                "produces": [ "application/octet-stream" ],
                "parameters": [
                    {
                        "name": "versionId",
                        "in": "path",
                        "description": "Version ID",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Success",
                        "schema": { "type": "file" }
                    }
                }
            }
...
Command line used for generation

java -jar swagger-codegen-cli-3.0.11.jar generate -l csharp-dotnet2 -i http://localhost:9220/swagger/v2/swagger.json

Steps to reproduce

Create a controler in ASP.Net Core that returns File. Example:

    [HttpGet("Versions/{versionId}/File")]
    [Produces("application/octet-stream")]
    [ProducesResponseType(200, Type = typeof(FileStreamResult))]
    public async Task<IActionResult> GetVersionFile(int versionId)
    {
        try
        {
            ApplicationVersion applicationVersion = await ApplicationService.GetVersion(versionId);
            var stream = await ApplicationService.GetVersionFileStream(versionId);
            return File(stream, "application/octet-stream", applicationVersion.FileName);
        }
        catch (InvalidOperationException)
        {
            return NotFound();
        }
    }

Add mapping in startup.

...
    c.MapType<FileStreamResult>(() => new Schema { Type = "file" });
...

Generate csharp-dotnet2 client and run your method.

frantuma commented 5 years ago

Thanks for reporting this! Can you detail what fix are you applying to the generated code?