Return a file stream using SwashBuckle

2019-07-14 20:25发布

问题:

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?

回答1:

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