8

I have rest controller which is returning HttpResponseMessage with Stream file as a content, something like this:

public class MyController : ApiController
{
    public HttpResponseMessage GetFile(string id)
    {
        try { 
            var stream = fileSystemUtils.GetFileStream(filePath); //Get Stream
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            response.Content = stream;
            return response;
        }
        catch (FileNotFoundException)
        {
            return new HttpResponseMessage(HttpStatusCode.NotFound);
        }
    }
}

When i call this method by ULR in browser everything is ok and i can download this file. Now i would like to download it using Swagger UI. Is some easy way to do this?

Olivier De Meulder
  • 2,493
  • 3
  • 25
  • 30
lukhol
  • 318
  • 2
  • 6
  • 18
  • 1
    When you go to that address, you are using an HTTP request, when you use Swagger, you use an AJAX request which is not suited for downloading files. While it can be done, you'd need to change the Swagger UI code – Camilo Terevinto May 22 '17 at 17:28

3 Answers3

8

In case someone else is looking for this, I did the following:

public class FileOperation : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        if (operation.OperationId.ToLower() == "apifileget")
        {
            operation.Produces = new[] { "application/octet-stream" };
            operation.Responses["200"].Schema = new Schema { Type = "file", Description = "Download file"};
        }
    }
}

//In the startup...
services.AddSwaggerGen(c =>
{
    //missing code...
    c.OperationFilter<FileOperation>();
});
Bianca
  • 382
  • 4
  • 12
6

This is what worked for me (.Net Core 2.2 and Swashbuckle 4.0.1):

[Route("api/[controller]")]
[ApiController]
public class DownloadController : ControllerBase
{
    [HttpGet("{name}")]
    [ProducesResponseType(typeof(byte[]), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(BadRequestObjectResult), 400)]
    public async Task<IActionResult> GetFile(string fileName)
    {
        var filePath = $"files/{fileName}"; // get file full path based on file name
        if (!System.IO.File.Exists(filePath))
        {
            return BadRequest();
        }
        return File(await System.IO.File.ReadAllBytesAsync(filePath), "application/octet-stream", fileName);
    }
}
Marcello
  • 1,099
  • 14
  • 18
1

Little bit late, but the correct way to do it is to use the Content-Disposition header and set the attachment flag. For example:

Content-Disposition: attachment; filename=myfile.xxx

Will indicate that it's an attachment. It's not required to set the Content-Type but it's a good practice to do so.

More info in this stack overflow question:

Do I need Content-Type: application/octet-stream for file download?

Sebastian
  • 4,770
  • 4
  • 42
  • 43