Return a file stream using SwashBuckle
Asked Answered
K

1

6

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?

Ketti answered 10/5, 2018 at 10:47 Comment(7)
The file stream is created by as System.IO.File.OpenRead(fileName)Ketti
Why the "Accept: application/octet-stream" won't see in the Swagger UI? I wonder if it works well except from UI?!Ketti
Perhaps a working example will help: swagger-net-test.azurewebsites.net/swagger/ui/…Havildar
...And the code behind my example is here: github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/…Havildar
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?Ketti
Ooo, your code uses another lib. "using Swagger.Net.Annotations;" - mine is using "Swashbuckle.Swagger.Annotations;" ...Ketti
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.Ketti
H
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

Havildar answered 11/5, 2018 at 13:9 Comment(1)
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<FileContentResult>(() => new Schema {type = "string", format = "binary"});Ketti

© 2022 - 2024 — McMap. All rights reserved.