Downloading byte[] of generated pdf using nodeservices in Asp.net Core 1.1
Asked Answered
C

1

7

I'm trying to download a nodeServices generated pdf file that is in the form of byte array. here is my original code:

[HttpGet]
[Route("[action]/{appId}")]
public async Task<IActionResult> Pdf(Guid appId, [FromServices] INodeServices nodeServices)
{
    // generateHtml(appId) is a function where my model is converted to html.
    // then nodeservices will generate the pdf for me as byte[].
    var result = await nodeServices.InvokeAsync<byte[]>("./pdf", 
            await generateHtml(appId));
    HttpContext.Response.ContentType = "application/pdf";
    HttpContext.Response.Headers.Add("x-filename", "myFile.pdf");
    HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "x-filename");
    HttpContext.Response.Body.Write(result, 0, result.Length);
    return new ContentResult();
}

This code was working fine, it will show the pdf file in the browser, eg. chrome, and when I try to download it, I get "failed, network error".

I've searched here and there, I saw some suggestions to return File instead:

return File(result, "application/pdf");

that didn't work either, another thing was adding "Content-Disposition" header:

HttpContext.Response.Headers.Add("Content-Disposition", string.Format("inline;filename={0}", "myFile.pdf"));

others suggested to use FileStreamResult, no good either. I realized that the problem could be about my generated file (byte[]) does not have a path or a link of his own, so I saved the bytes to my server, then got the file again by its path, then to memory stream, and finally return a file containing the memory stream:

var result = await nodeServices.InvokeAsync<byte[]>("./pdf", await generateHtml(appId));
var tempfilepath = Path.Combine(_environment.WebRootPath, $"temp/{appId}.pdf");

System.IO.File.WriteAllBytes(tempfilepath, result);

var memory = new MemoryStream();
using (var stream = new FileStream(tempfilepath, FileMode.Open))
{
    await stream.CopyToAsync(memory);
}
memory.Position = 0;

return File(memory, "application/pdf", Path.GetFileName(tempfilepath));

which worked! it showed the file in the browser, and I could download it, but, I did not want any files to be stored on my server, my question is, can't I just download the file without the need to store it?

Corridor answered 3/10, 2017 at 16:40 Comment(0)
S
11

You can still return the FileContentResult without converting the byte array to a stream. There is an overload of the File() method which takes fileContents as a byte array and the contentType as a string.

So you can refactor to something like:

public async Task<IActionResult> Pdf(Guid appId, [FromServices] INodeServices nodeServices)
{
    var result = await nodeServices.InvokeAsync<byte[]>("./pdf", 
            await generateHtml(appId));

    return File(result, "application/pdf","myFile.pdf");
}
Santasantacruz answered 3/10, 2017 at 19:10 Comment(3)
thanks alot !! I was aware of that overload, I even tried it as I explained in my question but it did not work for me before, I tried yours anyway and it turns out it works!!, so I went back in time to see the problem, which was that I did not comment out the HttpContext.Response.Con.. lines in my original code !! which made the file undownloadable. so thank you againCorridor
My pleasure. Glad you got it working. I'd entirely missed the part of the question where you said you'd tried return File(result, "application/pdf");... :-/Santasantacruz
i'm so glad you miss it ;)Corridor

© 2022 - 2024 — McMap. All rights reserved.