【问题标题】:Download file from WebAPI to angular 6 app将文件从 WebAPI 下载到 Angular 6 应用程序
【发布时间】:2019-06-22 13:49:30
【问题描述】:

我有 .NET webApi(.NET 4.5 框架)的 Angular 6 网络应用程序。

我正在做的是收集一些用户输入,向 webapi 发送请求。 Webapi 使用来自 db 的一些数据生成一个 excel 文件(xlsx 或 xlsm)。 现在我需要在用户机器上下载这个文件。 我已经在服务器上验证过,生成的文件是正确的,并在服务器上的临时目录中创建。 但它在用户计算机上下载为损坏的文件,Excel 无法打开它。

知道如何解决这个问题。

WebApi 代码

[System.Web.Http.HttpPut]
        public ActionResult Put(Parameters inputs)
        {
            var path = GenerateFile(inputs);
            string extension = new FileInfo(path).Extension;
            switch (extension)
            {
               case ".xls":
                    return new FilePathResult(path, "application/msexcel");
                case ".xlsx":
                    return new FilePathResult(path, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                case ".xlsm":
                    return new FilePathResult(path, "application/vnd.ms-excel.sheet.macroEnabled.12");

            }
        }

角度代码:

GenerateReprot() {
    this.http.put(this.webApiURL, this.Input, 'arraybuffer')
      .subscribe(
        result => {
          this.downLoadFile(result, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
          alert('file downloaded successfully. ');
        },
        error => {
          alert('error with downloading file.');
        }
      );
  }

    downLoadFile(data: any, type: string) {
    var blob = new Blob([data], { type: type });
    var url = window.URL.createObjectURL(blob);

    var pwa = window.open(url);
    if (!pwa || pwa.closed || typeof pwa.closed == 'undefined') {
      alert('Please disable your Pop-up blocker and try again.');
    }
  }

【问题讨论】:

  • 据我在文档中看到的put 方法将object 作为第三个参数,它包含属性responseType 实际上应该在您的 arraybuffer案例 - 也许有问题?
  • 我已经将第三个参数指定为arraybuffer this.http.put(this.webApiURL, this.Input, 'arraybuffer')
  • 但是您指定的方式错误。也许这会对你有所帮助 - angular.io/guide/http#requesting-non-json-data 但在你的情况下还有身体。
  • @Abhash786 确认正在使用的平台版本。 Web API 2+ 或核心?您标记显示 asp.net-web-api 并显示 System.Web.Http 命名空间,但该框架没有使用 ActionResult。很可能您返回了错误的模型类型,并且它被序列化为 JSON,这就是文件阅读器认为它们已损坏的原因。
  • @Abhash786 下载的数据在客户端是什么样子的?

标签: angular asp.net-web-api angular6


【解决方案1】:

Angular 在下载文件时遇到了一些奇怪的问题。只有提出请求,我无法下载文件。我不得不将请求分成两部分 1.提出文件准备请求 2. 获取文件下载请求

只有 put 请求,它总是下载 1KB 损坏的文件。 在 Angular 中,您也不需要使用任何数组缓冲区或 blob。它们还会导致一些奇怪的问题。

这里是代码(webapi)

[HttpPut]
        public string Put(Parameters inputs)
        {
            var file = GenerateFile(inputs);
            return Path.GetFileNameWithoutExtension(file);
        }

        [HttpGet]
        public HttpResponseMessage Get(string id) //id is file name returned from above put request
        {
            var result = Request.CreateResponse(HttpStatusCode.OK);
            var fullPath = Path.Combine(Path.GetTempPath(), id + ".xlsx");

            if (!File.Exists(fullPath))
            {
                fullPath = Path.Combine(Path.GetTempPath(), id + ".xlsm");

                if (!File.Exists(fullPath))
                    throw new FileNotFoundException(id);
            }
            var stream = new MemoryStream(File.ReadAllBytes(fullPath));
            result.Content = new StreamContent(stream);

            switch (Path.GetExtension(fullPath))
            {
                case ".xls":
                    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/msexcel");
                    break;
                case ".xlsx":
                    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                    break;
                case ".xlsm":
                    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-excel.sheet.macroEnabled.12");
                    break;
            }

            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = Path.GetFileName(fullPath)
            };

            return result;
        }

角度代码:

GenerateReprot() {

    this.http.put(this.webApiURL, this.Input)
      .subscribe(
        result => {
          var url = this.webApiURL + result.json();
          window.open(url)

          alert('file downloaded successfully: ');

        }),
      error => {
        alert('error while downloading file');
      };
  }

【讨论】:

    【解决方案2】:

    您的标签显示,而您显示System.Web.Http 命名空间,但该框架没有使用ActionResult。所以看起来你正在混合 MVC 和 Web API 之间的框架

    您很可能返回了错误的模型类型,并且它被序列化为 JSON,这就是文件阅读器认为它们已损坏的原因。

    以下假设是在 ApiController 中调用它

    [HttpPut]
    public IHttpActionResult Put(Parameters inputs) {
        var path = GenerateFile(inputs);
        var file = new FileInfo(path);
        string contentType = null;
        switch (file.Extension) {
            case ".xls":
                contentType = "application/msexcel";
            case ".xlsx":
                contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            case ".xlsm":
                contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
        }
    
        var stream = file.OpenRead();
    
        var content = new StreamContent(stream);
        content.Headers.ContentLength = stream.Length; 
        content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
            FileName = file.Name
        };
    
        var response = Request.CreateResponse(HttpStatusCode.OK);
        response.Content = content;
        return ResponseMessage(response);
    }
    

    【讨论】:

    • 感谢 Nkosi.... 这按预期工作,但问题仍然存在。在客户端,在 Angular 应用程序中,仅下载了 1KB 大小的损坏文件。
    • @Abhash786 在调试时单步执行代码并检查流的大小以确认数据正在正确加载。
    • Stream 包含所有数据......它是有角度的,这导致了这里的问题。
    • @Abhash786 然后在客户端打开文件时从响应中获取内容类型。现在,您拥有的代码具有硬编码的类型。
    • 我用一点技巧解决了这个问题。 webapi代码再次没有问题......这是角度下载文件的问题。为此,我不得不将 webapi 调用分解为两部分,一部分用于文件创建,另一部分用于文件下载。我也在添加我的代码。再次感谢您修复我的 webapi 问题。
    【解决方案3】:

    在您的 HTTP put 请求中尝试responseType: "blob"

    this.http.put(this.webApiURL, this.Input, { responseType: "blob" })
      .subscribe(
    ...
    );
    

    【讨论】:

    • 尝试了同样的方法,但它给了我运行时错误,例如不支持响应类型
    猜你喜欢
    • 2019-03-08
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 2018-12-05
    相关资源
    最近更新 更多