3

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'));
    });
}
5
  • Can you share the response the API returns? Commented Dec 31, 2019 at 13:44
  • You might have not exposed this header while sending response. Your server needs to send Access-Control-Expose-Headers header, so that your custom header is exposed to client. Commented Dec 31, 2019 at 13:45
  • @jonrsharpe Access-Control-Allow-Headers comes in when you make request from client to server. I think here Access-Control-Expose-Headers is needed. Am I making sense? Commented Dec 31, 2019 at 13:47
  • @Plochie you're right, thanks; I thought I was on developer.mozilla.org/en-US/docs/Glossary/…. Commented Dec 31, 2019 at 13:49
  • @NicholasK I have updated the question with my api method Commented Dec 31, 2019 at 13:51

1 Answer 1

5

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"); ;
}
Sign up to request clarification or add additional context in comments.

4 Comments

I used this: Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition"); And now I am getting: attachment; filename=something.csv; filename*=UTF-8''something.csv. Shall I do some string hacking og can I get the filename easier?
you can only get the information what you are sending from server. So if you want something custom, add some custom header say x-file-name while sending response. add this header in Access-Control-Expose-Headers and get this header at front end.
I have added Response.Headers.Add("x-file-name", "somethingNew.csv"); and I can see it in the response, but I can't get it in my Angular code: console.log(resp.headers.get('x-file-name'));
Have you added HttpContext.Response.AddHeader("Access-Control-Expose-Headers", "x-file-name"); ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.