ASP.NET Core – download file via byte[] vs stream

In ASP.NET Core application, we can create a webapi to have a download file function, in controller, create a method to return File object:

[HttpGet("download/{id}")]
public IActionResult DownloadFile(string id)
{
    ....
    return File(file, contentType, fileName);
}

The File class has several overload constructor:

FileStreamResult File(Stream fileStream, string contentType, bool enableRangeProcessing);
VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
VirtualFileResult File(string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
VirtualFileResult File(string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, bool enableRangeProcessing);
VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName);
VirtualFileResult File(string virtualPath, string contentType, bool enableRangeProcessing);
VirtualFileResult File(string virtualPath, string contentType);
FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
FileStreamResult File(Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
FileStreamResult File(Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, bool enableRangeProcessing);
FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName);
FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
FileContentResult File(byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
FileContentResult File(byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, bool enableRangeProcessing);
FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName);
FileContentResult File(byte[] fileContents, string contentType, bool enableRangeProcessing);
FileContentResult File(byte[] fileContents, string contentType);
FileStreamResult File(Stream fileStream, string contentType);

basically there are three ways to return a File object, 1. with virtual file path; 2. with file content byte array; 3. with file stream;

If your file stored in Azure Blob, there are two ways you can get it and download it via your ASP.NET Core web api: 1. download to a byte array from Azure Blob, and return File object with this byte array. 2. open a read stream of Azure Blob and return File object with this stream.

I’ve noticed that, if download to byte array and return it, this approach will cause a little memory leak and for a while, ASP.NET Core application will consume more and more memory, I guess because application host lots of byte array and GC sometimes will not collect them. When I switch to stream approach, the memory leak problem is gone. I guess because the download will let caller to get stream from blob directly, there is no byte array host in our application domain.

Leave a comment