FirstDivision
FirstDivision

Reputation: 1430

.NET Core 3 MVC download a file from HTTP and re-deliver to client using minimum memory

I have a .NET Core 3 MVC app that needs to read a file from one location over HTTP and then re-deliver it back out to the response. Some of these files will be ~200MB in size.

What I have works, but it reads the whole file into memory before sending the File result out to the client. Is there a way to make it essentially a passthrough where the read stream flows into the response stream so that very little memory is required on the server?

This is what I have now but I do not think will perform well with large files:

if (requestedFile != null)
{
    using (var client = new System.Net.Http.HttpClient())
    {
        using (var result = await client.GetAsync(requestedFile.DownloadUrl))
        {
            if (result.IsSuccessStatusCode)
            {
                var bytes = await result.Content.ReadAsByteArrayAsync();
                return File(bytes, "application/zip", "largefile.zip");
            }
        }
    }
}

I have also tried this which results in a runtime error of "Cannot access a closed Stream":

using (var client = new System.Net.Http.HttpClient())
{
    using (var httpResponseMessage = await client.GetAsync(requestedFile.DownloadUrl))
    {
        return File(await httpResponseMessage.Content.ReadAsStreamAsync(), "application/zip", "largefile.zip");

    }
}

Edit:

Solution after some trial and error was remocing all using statements and letting the FileStreamResult close the stream on its own. So I ended up with:

var client = new HttpClient();
var result = await client.GetAsync(requestedFile.DownloadUrl);
var stream = await result.Content.ReadAsStreamAsync();
return new FileStreamResult(stream, "application/zip")
{
    FileDownloadName = "largefile.zip"
};

Upvotes: 2

Views: 2473

Answers (2)

Sadegh Tohidi
Sadegh Tohidi

Reputation: 21

For Export Excel

 var client = new System.Net.Http.HttpClient();
            var comp = client.GetAsync($"RewardEmployee/ExportExcelCalculate?rewardConfigId={id}").Result;

`var stream = await result.Content.ReadAsStreamAsync();

 return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "ExportExcelCalculateRewardEmployee.xlsx");

Upvotes: 0

jle
jle

Reputation: 9489

One of the overloads for File is a Stream. Just get that URL as a Stream or read the response body as a stream and immediately return that in the overload:

var client = new System.Net.Http.HttpClient();
  
var result = await client.GetAsync(requestedFile.DownloadUrl);
var stream = await result.Content.ReadAsStreamAsync();
 
return File(stream,"application/pdf", "Invoice.pdf");

Note: this will fail if you wrap the Stream in a using block as the FileResult already closes the Stream.

Upvotes: 7

Related Questions