【问题标题】:How to correctly download files to Angular from ASP.NET Core?如何正确地将文件从 ASP.NET Core 下载到 Angular?
【发布时间】:2018-07-29 14:10:50
【问题描述】:

我在服务器上有一个文件要发送给客户端:

[HttpPost]
public IActionResult Test()
{
    byte[] bytes = System.IO.File.ReadAllBytes(Path.Combine(FilesFolder, "test.docx"));
    return File(bytes, _contentTypeWord);
}

我也试过

return PhysicalFile(pathUploadFile, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");

在我接受的客户处:

private _downloadFile(data: ArrayBuffer, fileName: string, contentType: string) {
    var blob = new Blob([data], { type: contentType });
    var url = window.URL.createObjectURL(blob);

    var link = document.createElement("a");
    link.setAttribute("href", url);
    link.setAttribute("download", fileName);
    link.style.display = "none";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

public test() {
    this.http.post("Diplom/Test", { }, {
        headers: this.headers(),
    }).subscribe(
        result => {
            this._downloadFile(result.arrayBuffer(), "test.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
        },
        error => {
            alert("Не удалось отредактировать файл");
            console.error(JSON.stringify(error));
        })
}

客户端收到的文件已损坏,无法打开。服务器上的文件很好,可以完美打开。生成的文件仍然无法打开,甚至重 2 倍(服务器上有 487 KB,客户端有 925 KB)。

【问题讨论】:

  • 尝试在后端和客户端之间发送 base64 编码。

标签: c# angular typescript asp.net-core


【解决方案1】:

您可以使用文件结果,只需提供将返回 FileContentResult 的 api 链接。

public IActionResult Download(// some parameter) 
{
   // get the file and convert it into a bytearray
   var locatedFile = ....
   return new FileContentResult(locatedFile, new 
       MediaTypeHeaderValue("application/octet"))
       {
           FileDownloadName = "SomeFileDownloadName.someExtensions"
       };
}

现在您只需要提供链接,浏览器就会知道如何处理它。那就不用自己动手了。

编辑: 我刚刚用angular测试了这种方法,使用angular时需要执行以下操作才能下载文件HttpClient。

首先你需要通过 npm 安装文件保护程序。

npm i --save file-saver

然后在你的模块中导入并包含 HttpClientModule

import { HttpClientModule } from '@angular/common/http';
...
@NgModule({
   imports: [
      HttpClientModule
      ...
   ]
...
})

现在继续为您服务并执行以下操作

import { HttpClient } from '@angular/common/http';
import { saveAs } from 'file-saver';

@Injectable()
export class MyFileService {

   public constructor(private http: HttpClient) {}

       public downloadFile() {
    this.http.get('my-api-url', { responseType: 'blob' }).subscribe(blob => {
       saveAs(blob, 'SomeFileDownloadName.someExtensions', {
          type: 'text/plain;charset=windows-1252' // --> or whatever you need here
       });
    });
}

然后处理 blob 并创建文件保存对话框。

【讨论】:

  • 没有帮助
  • 为什么不呢,发生了什么?
  • 没什么。在类 MediaTypeHeaderValue 中没有找到属性 FileDownloadName。所有相同的损坏文件来
  • 这是 FileConentResult 的属性,而不是 MediaTypeHeaderValue。能否提供 dotnet 代码?
  • 有相同的代码。只有在发送文件时,我才插入了您示例中的代码
【解决方案2】:

我不知道为什么问题中指定的选项不起作用。但我找到了一个解决方案,可以说是“在另一个森林里”。我不是很精通,所以我将描述解决问题的过程。首先,我会立即说问题出在客户端。服务器上的方法从一开始就正常工作。 我决定使用另一种方法来下载文件“获取”。并在forum 中看到了下一篇文章。从那里我得到了以下答案

this.httpClient
    .fetch(url, {method, body, headers})
    .then(response => response.blob())
    .then(blob => URL.createObjectURL(blob))
    .then(url => {
        window.open(url, '_blank');
        URL.revokeObjectURL(url);
    });

他也不为我工作。我就这么改了

    fetch(url, {
            method: 'POST',
            headers: this.headers()
        })
        .then(response => response.blob())
        .then(blob => URL.createObjectURL(blob))
        .then(url => {
            window.open(url, '_blank');
        });

因为这条线什么都没发生

URL.revokeObjectURL(url);

这个选项有效,但搞砸了。他用一个奇怪的名字保存了文件,没有扩展名。然后我就这么改了。

    fetch(url, {
            method: 'POST',
            headers: this.headers()
        })
            .then(response => response.blob())
            .then(blob => URL.createObjectURL(blob))
            .then(url => {
                var link = document.createElement("a");
                link.setAttribute("href", url);
                link.setAttribute("download", "test.docx");
                link.style.display = "none";
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            });

而且它有效! 我为英语道歉。我正在使用谷歌翻译器

【讨论】:

  • 谢谢它的工作,我用你的方法和 HttpClient.Get :``` this.http.get(path`, {responseType: 'blob'}).subscribe(file=> { const url :string = URL.createObjectURL(file); const link = document.createElement("a"); link.setAttribute("href", url); link.setAttribute("download", "Template.xlsx"); 链接。 style.display = "none"; document.body.appendChild(link); link.click(); document.body.removeChild(link); }); ```
  • 您不需要将孩子附加到正文(因此也将其删除)。 link.click() 就够了
【解决方案3】:

要下载任何文件,首先安装以下,

npm install rxjs --save
npm install file-saver --save

在你的组件中包含这些包(Angular 2+),

import { Observable } from 'rxjs';
import { saveAs } from 'file-saver';
import { map } from "rxjs/operators";
import { Subject } from 'rxjs';
import { HttpEventType, HttpClient } from '@angular/common/http';

前端代码,

<input type="button" placeholder="Download" value="Download" (click)="download(file)" />

角度代码,

download(file) {
        let fileName = file;
        let checkFileType = fileName.split('.').pop();
        var fileType;
        if (checkFileType == ".txt") {
            fileType = "text/plain";
        }
        if (checkFileType == ".pdf") {
            fileType = "application/pdf";
        }
        if (checkFileType == ".doc") {
            fileType = "application/vnd.ms-word";
        }
        if (checkFileType == ".docx") {
            fileType = "application/vnd.ms-word";
        }
        if (checkFileType == ".xls") {
            fileType = "application/vnd.ms-excel";
        }
        if (checkFileType == ".png") {
            fileType = "image/png";
        }
        if (checkFileType == ".jpg") {
            fileType = "image/jpeg";
        }
        if (checkFileType == ".jpeg") {
            fileType = "image/jpeg";
        }
        if (checkFileType == ".gif") {
            fileType = "image/gif";
        }
        if (checkFileType == ".csv") {
            fileType = "text/csv";
        }
        this.DownloadFile(fileName, fileType)
            .subscribe(
                success => {
                    saveAs(success, fileName);
                },
                err => {
                    alert("Server error while downloading file.");
                }
            );
    }

    DownloadFile(filePath: string, fileType: string): Observable<any> {

        let fileExtension = fileType;
        let input = filePath;

        return this.http.get(this.yourApiUrl + "?fileName=" + input, {
            responseType: 'blob',
            observe: 'response'
        })
            .pipe(
                map((res: any) => {
                    return new Blob([res.body], { type: fileExtension });
                })
            );
    }

.NET Core API 代码,

        [HttpGet]
        public async Task<FileStream> DownloadFile(string fileName)
        {
            return new FileStream(file, FileMode.Open, FileAccess.Read);
        }

【讨论】:

猜你喜欢
  • 2020-04-08
  • 2021-01-14
  • 1970-01-01
  • 2021-03-23
  • 2017-02-13
  • 1970-01-01
  • 2018-07-14
  • 1970-01-01
  • 2020-01-28
相关资源
最近更新 更多