如何从 dotnet core webapi 下载 ZipFile? [英] How to download a ZipFile from a dotnet core webapi?

查看:84
本文介绍了如何从 dotnet core webapi 下载 ZipFile?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 dotnet 核心 Web api 操作下载 zip 文件,但无法使其工作.我尝试通过 POSTMAN 和我的 Aurelia Http Fetch Client 调用该操作.

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.

我能够创建我想要的 ZipFile 并将其存储在系统上,但无法修复它,因此它通过 api 返回 zipfile.

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.

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

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.

任何帮助将不胜感激.

我的控制器操作

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

我的尝试

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

Note that what I've tried does not generate errors, it just doesn't seems to do anything.

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

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.

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(见上文)时,它什么也没做.

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.

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

           return result;

推荐答案

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

To put a long story short, the example below illustrates how to easily serve both a PDF as well as a ZIP through a dotnet-core api:

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

此示例有效™

This sample just works™

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

Notice in this case there is only one main difference between the two actions (besied the source file name, of course): the contentType that is returned.

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

The example above uses 'application/zip', as you've mentioned yourself, but it might just be required to serve a different mimetype (like 'application/octet*').

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

This leads to the speculation that either the zipfile cannot be read properly or that your webserver configuration might not be configured properly for serving .zip files.

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

The latter may differ based on whether you're running IIS Express, IIS, kestrel etc. But to put this to the test, you could try adding a zipfile to your ~/wwwroot folder, making sure you have enabled serving static files in your Status.cs, to see if you can download the file directly.

这篇关于如何从 dotnet core webapi 下载 ZipFile?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆