【问题标题】:How to download a ZipFile from a dotnet core webapi?如何从 dotnet core webapi 下载 Zip 文件?
【发布时间】:2017-05-13 23:50:32
【问题描述】:

我正在尝试从 dotnet core web api 操作下载一个 zip 文件,但我无法使其正常工作。我尝试通过 POSTMAN 和我的 Aurelia Http Fetch Client 调用该操作。

我可以按照自己的意愿创建 ZipFile 并将其存储在系统上,但无法修复它,因此它通过 api 返回 zipfile。

用例:用户选择几个图片集并单击下载按钮。图片集合的 id 被发送到 api 并创建一个 zip 文件,其中包含包含图片的每个图片集合的目录。该 zip 文件将返回给用户,以便他/她可以将其存储在他们的系统中。

任何帮助将不胜感激。

我的控制器操作

      /// <summary>
      /// Downloads a collection of picture collections and their pictures
      /// </summary>
      /// <param name="ids">The ids of the collections to download</param>
      /// <returns></returns>
      [HttpPost("download")]
      [ProducesResponseType(typeof(void), (int) HttpStatusCode.OK)]
      public async Task<IActionResult> Download([FromBody] IEnumerable<int> 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 => 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 => archive.CreateEntryFromFile(x.FilePath, $"{directory}/{x.FileName}"));
                }
           }

           // What to do here so it returns the just created zip file?
      }
 }

我的 aurelia fetch 客户端函数:

/**
 * Downloads all pictures from the picture collections in the ids array
 * @params ids The ids of the picture collections to download
 */
download(ids: Array<number>): Promise<any> {
    return this.http.fetch(AppConfiguration.baseUrl + this.controller + 'download', {
        method: 'POST',
        body: json(ids)
    })
}

我的尝试

请注意,我尝试过的操作不会产生错误,它似乎什么也没做。

1) 创建我自己的 FileResult(就像我以前使用旧 ASP.NET 所做的那样)。当我通过邮递员或应用程序调用它时,根本看不到正在使用的标题。

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);
      }
 }

}

2) https://stackoverflow.com/a/34857134/2477872

什么都不做。

      HttpContext.Response.ContentType = "application/zip";
           var result = new FileContentResult(System.IO.File.ReadAllBytes(zipFile), "application/zip")
           {
                FileDownloadName = Path.GetFileName(zipFile)
           };
           return result;

我已经使用测试虚拟 PDF 文件进行了尝试,并且似乎可以与 POSTMAN 一起使用。但是当我尝试将其更改为 zipfile(见上文)时,它什么也没做。

  HttpContext.Response.ContentType = "application/pdf";
           var result = new FileContentResult(System.IO.File.ReadAllBytes("THE PATH/test.pdf"), "application/pdf")
           {
                FileDownloadName = "test.pdf"
           };

           return result;

【问题讨论】:

    标签: asp.net-web-api download .net-core zipfile aurelia-fetch-client


    【解决方案1】:

    长话短说,下面的示例说明了如何通过 dotnet-core api 轻松提供 PDF 和 ZIP:

    /// <summary>
    /// Serves a file as PDF.
    /// </summary>
    [HttpGet, Route("{filename}/pdf", Name = "GetPdfFile")]
    public IActionResult GetPdfFile(string filename)
    {
        const string contentType = "application/pdf";
        HttpContext.Response.ContentType = contentType;
        var result = new FileContentResult(System.IO.File.ReadAllBytes(@"{path_to_files}\file.pdf"), contentType)
        {
            FileDownloadName = $"{filename}.pdf"
        };
    
        return result;
    }
    
    /// <summary>
    /// Serves a file as ZIP.
    /// </summary>
    [HttpGet, Route("{filename}/zip", Name = "GetZipFile")]
    public IActionResult GetZipFile(string filename)
    {
        const string contentType ="application/zip";
        HttpContext.Response.ContentType = contentType;
        var result = new FileContentResult(System.IO.File.ReadAllBytes(@"{path_to_files}\file.zip"), contentType)
        {
            FileDownloadName = $"{filename}.zip"
        };
    
        return result;
    }
    

    此示例正常工作™

    请注意,在这种情况下,这两个操作之间只有一个主要区别(当然,除了源文件名之外):返回的 contentType。

    上面的示例使用“application/zip”,正如您自己提到的,但它可能只是需要提供不同的 mimetype(如“application/octet*”)。

    这导致人们猜测无法正确读取 zip 文件,或者您的网络服务器配置可能未正确配置以提供 .zip 文件。

    后者可能会根据您是否运行 IIS Express、IIS、kestrel 等而有所不同。但要对此进行测试,您可以尝试将 zipfile 添加到您的 ~/wwwroot 文件夹,确保您已启用静态服务您的 Status.cs 中的文件,看看您是否可以直接下载该文件。

    【讨论】:

    • 如果文件很大,会因为字节数组而消耗大量内存。有没有办法在不缓冲的情况下流式传输内容?
    猜你喜欢
    • 2023-03-16
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 2017-06-16
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    相关资源
    最近更新 更多