PNR
PNR

Reputation: 597

Getting filename from server when downloading file from web.api in Angular 8

I have am getting a file from my web.api (.net core) in my Angular 8 application, but I can't get the file name from the server... If I look at the response in Fiddler, then I can see the filename in the response header (Content-Disposition).

I have the following method in my service:

public getAsCsv(taskId: number): Observable<HttpResponse<Blob>> {
    return this.httpClient.get<Blob>(`${this.apiBaseUrl}/getAsCsv/${taskId}`, {
        observe: 'response',
        responseType: 'blob' as 'json'
      });
}

In my component I have this code:

 public export(taskSmall: TaskSmall) {
    this.taskApiService.getAsCsv(taskSmall.id).subscribe((resp: HttpResponse<Blob>) => {
        console.log(resp.headers.get('Content-Disposition')); // is writing null in the console
        const filename = resp.headers.get('Content-Disposition');
        saveAs(resp.body, filename);
    });
}

My web api method look like this:

   [HttpGet("getAsCsv/{taskId}")]
    [Authorize(Roles = RoleConstants.Admin)]
    public async Task<IActionResult> GetAsCsv(int taskId)
    {
        var result = await _mediator.Send(new GetTaskAsCsvCommand(taskId), CancellationToken.None);

        byte[] byteArray = Encoding.ASCII.GetBytes(result.Value);

        var response = File(byteArray, "application/csv");
        response.FileDownloadName = "something.csv";
        return response;
    }

If I try to get the parameter "Content-Type" from the header it show the right value (application/csv).

What am I doing wrong?

UPDATE Thanks to @Plochie I ended up doing this:

API:

 [HttpGet("getAsCsv/{taskId}")]
    [Authorize(Roles = RoleConstants.Admin)]
    public async Task<IActionResult> GetAsCsv(int taskId)
    {
        var result = await _mediator.Send(new GetTaskAsCsvCommand(taskId), CancellationToken.None);

        byte[] byteArray = Encoding.ASCII.GetBytes(result.Value);

        Response.Headers.Add("x-file-name", "something.csv");
        Response.Headers.Add("Access-Control-Expose-Headers", "x-file-name");

        return File(byteArray, "application/csv"); ;
    }

Client:

    public export(taskSmall: TaskSmall) {
    this.taskApiService.getAsCsv(taskSmall.id).subscribe((resp: HttpResponse<Blob>) => {
        saveAs(resp.body, resp.headers.get('x-file-name'));
    });
}

Upvotes: 3

Views: 3222

Answers (1)

Plochie
Plochie

Reputation: 4117

You might have not exposed this header while sending response. Your server needs to send Access-Control-Expose-Headers header, so that your header is exposed to client.

Here you can expose Content-Disposition header or create your own custom header x-file-name with the filename as value and expose this custom header.

Documentation:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

[HttpGet("getAsCsv/{taskId}")]
[Authorize(Roles = RoleConstants.Admin)]
public async Task<IActionResult> GetAsCsv(int taskId)
{
   var result = await _mediator.Send(new GetTaskAsCsvCommand(taskId), CancellationToken.None);

   byte[] byteArray = Encoding.ASCII.GetBytes(result.Value);

   Response.Headers.Add("x-file-name", "something.csv");
   Response.Headers.Add("Access-Control-Expose-Headers", "x-file-name");

   return File(byteArray, "application/csv", "something.csv"); ;
}

Upvotes: 5

Related Questions