0

How to implement the following function in IHttpActionResult action, Web API controller?

Do I need to modify the HttpResponseBase to something else?

public void ZipFilesToResponse(HttpResponseBase response, IEnumerable<Asset> files, string zipFileName)
{
    using (var zipOutputStream = new ZipOutputStream(response.OutputStream))
    {
        zipOutputStream.SetLevel(0); // 0 - store only to 9 - means best compression
        response.BufferOutput = false;
        response.AddHeader("Content-Disposition", "attachment; filename=" + zipFileName);
        response.ContentType = "application/octet-stream";

        foreach (var file in files)
        {
            var entry = new ZipEntry(file.FilenameSlug())
            {
                DateTime = DateTime.Now,
                Size = file.Filesize
            };
            zipOutputStream.PutNextEntry(entry);
            storageService.ReadToStream(file, zipOutputStream);
            response.Flush();
            if (!response.IsClientConnected)
            {
               break;
            }
        }
        zipOutputStream.Finish();
        zipOutputStream.Close();
    }
    response.End();
}

To be utilized here:

[HttpPost]
[Route("DownloadFiles/{company_id}")]
public IHttpActionResult DownloadFiles(Int64 company_id, TasksFilterModel searchModel)
{
     var files = .....;
     ZipFilesToResponse(_______,files,"download.zip");
     return ????
}
Eric B
  • 691
  • 5
  • 11
Shyamal Parikh
  • 2,988
  • 4
  • 37
  • 78
  • I don't have the full answer, but it may help to read this: https://stackoverflow.com/a/47397666/1220550 – Peter B Dec 22 '17 at 14:37

1 Answers1

1

Your current ZipFilesToResponse method is built more for regular MVC, not Web API. One option would be to simply move this action into an MVC controller instead of a Web API controller.

public class MyController : Controller
{
    [HttpPost]
    [Route("DownloadFiles/{company_id}")]
    public void DownloadFiles(Int64 company_id, TasksFilterModel searchModel)
    {
         var files = ...;
         ZipFilesToResponse(HttpContext.Response, files, "download.zip");
    }
}

You do not need to return anything since your ZipFilesToResponse method writes directly to the HttpContext.Response object.

Alternatively, if you want to stick with purely Web API, we can modify the ZipFilesToResponse method to create a HttpResponseMessage, and then return that from your action.

[Route("DownloadFiles")]
[HttpGet]
public HttpResponseMessage DownloadFiles()
{
    var files = ...;
    return ZipContentResult(files, "download.zip");
}

protected HttpResponseMessage ZipContentResult(IEnumerable<Asset> files, string zipFileName)
{
    var pushStreamContent = new PushStreamContent((stream, content, context) =>
    {
        using (var zipOutputStream = new ZipOutputStream(stream))
        {
            zipOutputStream.SetLevel(0); // 0 - store only to 9 - means best compression

            foreach (var file in files)
            {
                var entry = new ZipEntry(file.FilenameSlug())
                {
                    DateTime = DateTime.Now,
                    Size = file.Filesize
                };
                zipOutputStream.PutNextEntry(entry);
                storageService.ReadToStream(file, zipOutputStream);
                stream.Flush();
             }
             zipOutputStream.Finish();
             zipOutputStream.Close();
        }
        stream.Close();
    }, "application/zip");

    pushStreamContent.Headers.Add("Content-Disposition", "attachment; filename=" + zipFileName);

    return new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
}
Eric B
  • 691
  • 5
  • 11
  • 1
    Also, to return an IHttpActionResult in DownloadFiles with your code one can write `return ResponseMessage(ZipContentResult(files));`. Although it doesn't really gives any additional benefit. – ckuri Dec 22 '17 at 17:35
  • On the frontend download doesn't begin automatically. Am I missing anything? – Shyamal Parikh Dec 22 '17 at 19:12
  • @ShyamalParikh What happens when you hit the endpoint (/DownloadFiles/...)? Any errors returned? I realized in my second example I used [HttpGet] instead of [HttpPost], make sure to change that to fit your requirements. – Eric B Dec 22 '17 at 19:57
  • The client receives the file however download modal isn't trigger to save the file on client – Shyamal Parikh Dec 23 '17 at 04:51
  • Ok so the download is being triggered however, there's an error on opening the zip file – Shyamal Parikh Dec 23 '17 at 08:51