resumable download c#
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
namespace Sample.Controllers
{
public class HomeController : Controller
{
[HttpHead]
[HttpGet]
public void Download()
{
// File to download
FileInfo pdf = new FileInfo(@"D:\Edge\bigfile.bin");
if (Request.Method == "HEAD")
SetResponseHeaders(pdf);
else
DownloadContent(pdf);
}
private IActionResult DownloadContent(FileInfo pdf)
{
Response.Headers.Add("Accept-Ranges", "bytes");
Response.Headers.Add("Content-Disposition", $"attachment; filename={pdf.Name}");
//
long start = 1, end = pdf.Length, length;
byte[] buffer;
if (Request.Headers["Range"].Count > 0 && Request.Headers["Range"][0] != null)
{
string[] range = Request.Headers["Range"][0].Split(new[] { '=', '-' });
if (range.Length > 1) long.TryParse(range[1], out start);
if (start <= 0 || start > pdf.Length) start = 1;
if (range.Length > 2) long.TryParse(range[2], out end);
if (end > pdf.Length || end <= 0) end = pdf.Length;
}
else
{
// If no Range header found, send the entire file content
start = 1;
end = pdf.Length;
}
length = end - start + 1;
buffer = new byte[length];
Response.ContentLength = length;
if (Request.Headers["Range"].Count > 0)
{
Response.StatusCode = 206;
Response.Headers.Add("Content-Range", $"bytes {start}-{end}/{pdf.Length}");
}
else
{
Response.StatusCode = 200;
}
FileStream fs = new FileStream(pdf.FullName, FileMode.Open);
if (fs.CanSeek)
{
fs.Seek(start - 1, SeekOrigin.Begin);
int read = fs.Read(buffer, 0, (int)length);
fs.Close();
Response.Body.Write(buffer, 0, buffer.Length);
}
else
{
//Response.Body.Write($"Can't return content range.");
}
}
private void SetResponseHeaders (FileInfo pdf)
{
Response.StatusCode = 200;
Response.Headers.Add("Accept-Ranges", "bytes");
Response.ContentType = "application/octet-stream"; // Change MIME based on file type
Response.Headers.Add("Content-Disposition", $"attachment; filename={pdf.Name}");
Response.ContentLength = pdf.Length;
}
}
}