5

I want to return a file stream using SwashBuckle

    [System.Web.Http.HttpGet]
    [System.Web.Http.Route("Files/{uid}/file")]
    [SwaggerResponse(HttpStatusCode.OK, Type = typeof(Byte[]))]
    public HttpResponseMessage DownloadFile(String uid, String fileName)
    {
        return Safe.Execute(() =>
        {
            var api = new FileApi();
            var stream = api.GetFile(uid, fileName);

            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition =
                     new ContentDispositionHeaderValue("attachment")
                     {
                         FileName = CalcFileName(fileName)
                     };
            return result;
        });
    }

And I see that the file is returned, but... somehow... encoded. A 3798 long file becomes 5789 byte after download through UI, and the content of the file is very similar to the expected, but extra bytes are included, like it would interpreted as a String and became an UTF-8 encoded version.

Nothing changes, when I replace it as:

    [SwaggerResponse(HttpStatusCode.OK, Type = typeof(Stream))]

The Swagger generated desciptor looks as:

        "produces": [    
          "application/json",    
          "text/json",    
          "application/xml",    
          "text/xml"    
        ],    
        ...
        "responses": {    
          "200": {    
            "description": "OK",    
            "schema": {    
              "format": "byte",    
              "type": "string"
        }

Any idea how to implement returning a file stream from the controller method?

Zoltan Hernyak
  • 989
  • 1
  • 14
  • 35
  • The file stream is created by as System.IO.File.OpenRead(fileName) – Zoltan Hernyak May 10 '18 at 11:20
  • Why the "Accept: application/octet-stream" won't see in the Swagger UI? I wonder if it works well except from UI?! – Zoltan Hernyak May 10 '18 at 11:24
  • Perhaps a working example will help: http://swagger-net-test.azurewebsites.net/swagger/ui/index?filter=Image#/Image/Image_Put – Helder Sepulveda May 10 '18 at 12:36
  • ...And the code behind my example is here: https://github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/Controllers/ImageController.cs#L31 – Helder Sepulveda May 10 '18 at 13:15
  • The "[SwaggerResponse(200, "Download an image", mediaType: "application/octet-stream")] attribute now cannot be applied, "mediaType" is unknown. Only Type parameter is valid here. May your code uses an older version of SwashBuckle? – Zoltan Hernyak May 11 '18 at 05:01
  • Ooo, your code uses another lib. "using Swagger.Net.Annotations;" - mine is using "Swashbuckle.Swagger.Annotations;" ... – Zoltan Hernyak May 11 '18 at 05:03
  • It seems to me that the error is on the SwashBuckle UI. When I use curl directly - the file is downloaded good. Through the SwashBuckle UI, the file is bad. :( I wonder how can I describe the API method well to the UI. – Zoltan Hernyak May 11 '18 at 10:13

1 Answers1

2

To describe the API method you can use an IOperationFilter in your swagger config

public class UpdateFileDownloadOperations : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry s, ApiDescription a)
    {
        if (operation.operationId == "DownloadFile_Get")
        {
            operation.produces = new[] { "application/octet-stream" };
        }
    }
}

If you never used the filters look at the project's page: https://github.com/domaindrivendev/Swashbuckle/blob/e0053e1864defa3c4f73ca2a960eb876e257cc9e/Swashbuckle.Dummy.Core/App_Start/SwaggerConfig.cs


In the example on my comment I'm using Swagger-Net very similar, but I've made some improvements and probably you noticed that it uses the latest Swagger-UI

Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56
  • 4
    Thanks! A think I succeeded. I added [SwaggerResponse(HttpStatusCode.OK, "Download a file.", typeof(FileContentResult))] attribute to the method, then added a custom mapping to the SwaggerConfig.cs: c.MapType(() => new Schema {type = "string", format = "binary"}); – Zoltan Hernyak May 16 '18 at 11:21