title: How to download a ZipFile from a dotnet core webapi?
body: <p>I am trying to download a zip file from a dotnet core web api action, but I can't make it work. I tried calling the action via POSTMAN and my Aurelia Http Fetch Client.</p>
  
  <p>I am able to create the ZipFile like I want it and store it on the system, but can't fix it so it returns the zipfile via the api. </p>
  
  <p>Use-case: User selects a couple of picture collections and clicks the download button. The ids of the picture collections gets send to the api and a zipfile is created which contains a directory for every picture collection which holds the pictures. That zipfile is returned to the user so he/she can store it on their system.</p>
  
  <p>Any help would be appreciated.</p>
  
  <p><strong>My controller action</strong></p>
  
  <pre><code>      /// &lt;summary&gt;
        /// Downloads a collection of picture collections and their pictures
        /// &lt;/summary&gt;
        /// &lt;param name="ids"&gt;The ids of the collections to download&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        [HttpPost("download")]
        [ProducesResponseType(typeof(void), (int) HttpStatusCode.OK)]
        public async Task&lt;IActionResult&gt; Download([FromBody] IEnumerable&lt;int&gt; ids)
        {
             // Create new zipfile
             var zipFile = $"{_ApiSettings.Pictures.AbsolutePath}/collections_download_{Guid.NewGuid().ToString("N").Substring(0,5)}.zip";
  
             using (var repo = new PictureCollectionsRepository())
             using (var picturesRepo = new PicturesRepository())
             using (var archive = ZipFile.Open(zipFile, ZipArchiveMode.Create))
             {
                  foreach (var id in ids)
                  {
                       // Fetch collection and pictures
                       var collection = await repo.Get(id);
                       var pictures = await picturesRepo
                            .GetAll()
                            .Where(x =&gt; x.CollectionId == collection.Id)
                            .ToListAsync();
  
                       // Create collection directory IMPORTANT: the trailing slash
                       var directory = $"{collection.Number}_{collection.Name}_{collection.Date:yyyy-MM-dd}/";
                       archive.CreateEntry(directory);
  
                       // Add the pictures to the current collection directory
                       pictures.ForEach(x =&gt; archive.CreateEntryFromFile(x.FilePath, $"{directory}/{x.FileName}"));
                  }
             }
  
             // What to do here so it returns the just created zip file?
        }
   }
  </code></pre>
  
  <p><strong>My aurelia fetch client function:</strong></p>
  
  <pre><code>/**
   * Downloads all pictures from the picture collections in the ids array
   * @params ids The ids of the picture collections to download
   */
  download(ids: Array&lt;number&gt;): Promise&lt;any&gt; {
      return this.http.fetch(AppConfiguration.baseUrl + this.controller + 'download', {
          method: 'POST',
          body: json(ids)
      })
  }
  </code></pre>
  
  <p><strong>What I've tried</strong></p>
  
  <p>Note that what I've tried does not generate errors, it just doesn't seems to do anything.</p>
  
  <p>1) Creating my own FileResult (like I used to do with older ASP.NET). Can't see the headers being used at all when I call it via postman or the application.</p>
  
  <pre><code>return new FileResult(zipFile, Path.GetFileName(zipFile), "application/zip");
  
   public class FileResult : IActionResult
   {
        private readonly string _filePath;
        private readonly string _contentType;
        private readonly string _fileName;
  
        public FileResult(string filePath, string fileName = "", string contentType = null)
        {
             if (filePath == null) throw new ArgumentNullException(nameof(filePath));
  
             _filePath = filePath;
             _contentType = contentType;
             _fileName = fileName;
        }
  
        public Task ExecuteResultAsync(ActionContext context)
        {
             var response = new HttpResponseMessage(HttpStatusCode.OK)
             {
                  Content = new ByteArrayContent(System.IO.File.ReadAllBytes(_filePath))
             };
  
             if (!string.IsNullOrEmpty(_fileName))
                  response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                  {
                       FileName = _fileName
                  };
  
             response.Content.Headers.ContentType = new MediaTypeHeaderValue(_contentType);
  
             return Task.FromResult(response);
        }
   }
  </code></pre>
  
  <p>}</p>
  
  <p>2) <a href="https://stackoverflow.com/a/34857134/2477872">https://stackoverflow.com/a/34857134/2477872</a></p>
  
  <p>Does nothing.</p>
  
  <pre><code>      HttpContext.Response.ContentType = "application/zip";
             var result = new FileContentResult(System.IO.File.ReadAllBytes(zipFile), "application/zip")
             {
                  FileDownloadName = Path.GetFileName(zipFile)
             };
             return result;
  </code></pre>
  
  <p>I've tried it with a test dummy PDF file and that seemed to work with POSTMAN. But when I try to change it to the zipfile (see above) it does nothing.</p>
  
  <pre><code>  HttpContext.Response.ContentType = "application/pdf";
             var result = new FileContentResult(System.IO.File.ReadAllBytes("THE PATH/test.pdf"), "application/pdf")
             {
                  FileDownloadName = "test.pdf"
             };
  
             return result;
  </code></pre>