How to correctly download files to Angular from ASP.NET Core?

前端 未结 3 1186
粉色の甜心
粉色の甜心 2020-12-12 00:25

I have a file on the server that I want to send to the client:

[HttpPost]
public IActionResult Test()
{
    byte[] bytes = System.IO.File.ReadAllBytes(Path.C         


        
相关标签:
3条回答
  • 2020-12-12 00:40

    To download any file, first install the following,

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

    Include these packages in your component(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';
    

    Front-end code,

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

    Angular Code,

    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 code,

            [HttpGet]
            public async Task<FileStream> DownloadFile(string fileName)
            {
                return new FileStream(file, FileMode.Open, FileAccess.Read);
            }
    
    0 讨论(0)
  • 2020-12-12 00:49

    You can use a file result and just provide an api link that will return a FileContentResult.

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

    Now you only need to provide the link and browser will know how to handle it. No need to do it yourself then.

    Edit: I just tested this approach with angular, you need to do the following to download the file when using angulars HttpClient.

    First you need to install file-saver via npm.

    npm i --save file-saver
    

    Then in your module import and include HttpClientModule

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

    Now go ahead to your service and do the following

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

    Then blob is handled and a file-save dialog is created.

    0 讨论(0)
  • 2020-12-12 00:49

    I do not know why the option specified in the question does not work. But I found a solution, so to say "in another forest". I'm not very versed, so I'll just describe the process of solving the problem. For the beginning I will immediately say that the problem was on the client's side. The method on the server worked correctly from the start. I decided to use another method to download the files "fetch". And came across the next post in the forum. From there I took the following answer

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

    He did not work for me either. I changed it so

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

    Because of this line nothing happened

    URL.revokeObjectURL(url);
    

    This option worked, but with screwed. He saved the file with a strange name and no extension. Then I changed it so.

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

    And it works! I apologize for the English. I'm using Google translator

    0 讨论(0)
提交回复
热议问题