ASP.NET Core下載大文件的實現


當我們的ASP.NET Core網站需要支持下載大文件時,如果不做控制可能會導致用戶在訪問下載頁面時發生無響應,使得瀏覽器崩潰。可以參考如下代碼來避免這個問題。
 
關於此代碼的幾點說明:
  1. 將數據分成較小的部分,然后將其移動到響應輸出流以供下載,從而獲取這些數據。
  2. 根據下載的文件類型來指定 Response.ContentType 。(這個網址可以找到大部分文件類型的對照表:http://tool.oschina.net/commons
  3. 在每次調用Response.Body.Write后記得調用 Response.Body.Flush()
  4. 在循環下載的過程中使用 HttpContext.RequestAborted.IsCancellationRequested 這個判斷可以幫助程序盡早發現連接是否正常。若不正常,可以及早放棄下載,以釋放所占用的服務器資源。
 
本例使用ASP.NET Core MVC中Controller的Action來演示大文件的下載代碼,根據需要也可以改為其它方式(例如ASP.NET Core的中間件)來做下載。
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Web;

namespace AspNetCoreDownload.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// DownloadBigFile用於下載大文件,循環讀取大文件的內容到服務器內存,然后發送給客戶端瀏覽器
        /// </summary>
        public IActionResult DownloadBigFile()
        {
            var filePath = @"D:\Download\測試文檔.xlsx";//要下載的文件地址,這個文件會被分成片段,通過循環逐步讀取到ASP.NET Core中,然后發送給客戶端瀏覽器
            var fileName = Path.GetFileName(filePath);//測試文檔.xlsx

            int bufferSize = 1024;//這就是ASP.NET Core循環讀取下載文件的緩存大小,這里我們設置為了1024字節,也就是說ASP.NET Core每次會從下載文件中讀取1024字節的內容到服務器內存中,然后發送到客戶端瀏覽器,這樣避免了一次將整個下載文件都加載到服務器內存中,導致服務器崩潰

            Response.ContentType = "application/vnd.ms-excel";//由於我們下載的是一個Excel文件,所以設置ContentType為application/vnd.ms-excel

            var contentDisposition = "attachment;" + "filename=" + HttpUtility.UrlEncode(fileName);//在Response的Header中設置下載文件的文件名,這樣客戶端瀏覽器才能正確顯示下載的文件名,注意這里要用HttpUtility.UrlEncode編碼文件名,否則有些瀏覽器可能會顯示亂碼文件名
            Response.Headers.Add("Content-Disposition", new string[] { contentDisposition });

            //使用FileStream開始循環讀取要下載文件的內容
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                using (Response.Body)//調用Response.Body.Dispose()並不會關閉客戶端瀏覽器到ASP.NET Core服務器的連接,之后還可以繼續往Response.Body中寫入數據
                {
                    long contentLength = fs.Length;//獲取下載文件的大小
                    Response.ContentLength = contentLength;//在Response的Header中設置下載文件的大小,這樣客戶端瀏覽器才能正確顯示下載的進度

                    byte[] buffer;
                    long hasRead = 0;//變量hasRead用於記錄已經發送了多少字節的數據到客戶端瀏覽器

                    //如果hasRead小於contentLength,說明下載文件還沒讀取完畢,繼續循環讀取下載文件的內容,並發送到客戶端瀏覽器
                    while (hasRead < contentLength)
                    {
                        //HttpContext.RequestAborted.IsCancellationRequested可用於檢測客戶端瀏覽器和ASP.NET Core服務器之間的連接狀態,如果HttpContext.RequestAborted.IsCancellationRequested返回true,說明客戶端瀏覽器中斷了連接
                        if (HttpContext.RequestAborted.IsCancellationRequested)
                        {
                            //如果客戶端瀏覽器中斷了到ASP.NET Core服務器的連接,這里應該立刻break,取消下載文件的讀取和發送,避免服務器耗費資源
                            break;
                        }

                        buffer = new byte[bufferSize];

                        int currentRead = fs.Read(buffer, 0, bufferSize);//從下載文件中讀取bufferSize(1024字節)大小的內容到服務器內存中

                        Response.Body.Write(buffer, 0, currentRead);//發送讀取的內容數據到客戶端瀏覽器
                        Response.Body.Flush();//注意每次Write后,要及時調用Flush方法,及時釋放服務器內存空間

                        hasRead += currentRead;//更新已經發送到客戶端瀏覽器的字節數
                    }
                }
            }

            return new EmptyResult();
        }
    }
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM