最近要使用ASP.NET CORE WEBAPI用來下載文件,使用的.NET CORE 3.1。考慮以下場景:web
通過簡單的調研,獲得如下結論。c#
創建好ASP.NET CORE WEBAPI工程,把生成文件的代碼獨立出來一個函數。我這裏須要是下載一個CSV格式的文件,所以生成一個CSV文件。
對於磁盤上的文件,可使用FileStream對象,因爲我這裏須要運行中生成這個文件,須要使用MemoryStream。api
using var stream = new MemoryStream(); using var writer = new StreamWriter(stream); //生成標題 var propCollection = ttype.GetProperties(); foreach (var n in propCollection) { writer.Write(n.Name); writer.Write(","); } writer.WriteLine(); //生成內容 foreach (var item in res) { foreach (var n in propCollection) { writer.Write(Convert.ToString(n.GetValue(item))); writer.Write(","); } writer.WriteLine(); }
- 請不要考慮裏面反射的相關內容,按照本身的邏輯生成CSV便可,我只是懶得改代碼而已。
- 代碼中使用到了一些新的語法特性,請注意對低版本的.NET不必定適用。
直接返回Stream對象給Controller處理,處理代碼以下:
var res = await info.GetAllQueryResult(); var actionresult = new FileStreamResult(res, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/csv")); return actionresult;
CSV的Content-Type是text/csv,若是下載別的文件,請自行查詢MIME格式。瀏覽器
直接執行上面的代碼,直接報錯「沒法讀取已經關閉的流」。猜想是離開using語句塊的時候,stream自動被關閉了。改動很簡單,去掉using語句,再也不報相同錯誤。app
可是返回的文件長度一直是0,單步調試發現Writer執行完畢以後,stream返回的長度是0,內容實際上並無寫入,想起有一個Flush(),能夠添加以確保數據寫入。async
單步顯示stream長度有了,可是返回的長度仍是0。繼續單步調試發現Stream的Postion是停在文件結尾的,這個和直接開始讀取文件徹底不同,文件讀取通常是從開頭開始的,因而直接設置Postion爲0,問題解決。函數
下載可以成功了,可是文件名一直顯示的是隨機生成的,體驗不好。設置一下FileDownloadName便可。.net
核心代碼以下:調試
public async Task<Stream> GetAllQueryResult() { var stream = new MemoryStream(); var writer = new StreamWriter(stream); //生成標題 var propCollection = ttype.GetProperties(); foreach (var n in propCollection) { writer.Write(n.Name); writer.Write(","); } writer.WriteLine(); //生成內容 foreach (var item in res) { foreach (var n in propCollection) { writer.Write(Convert.ToString(n.GetValue(item))); writer.Write(","); } writer.WriteLine(); } writer.Flush(); stream.Position = 0; return stream; }
[HttpPost("file")] [ProducesResponseType(typeof(FileResult), Status200OK)] public async Task<FileResult> Download() { var info = new Info(); var res = await info.GetAllQueryResult(); var actionresult = new FileStreamResult(res, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/csv")); actionresult.FileDownloadName = "Carinfos.csv"; //Response.ContentLength = res.Length; return actionresult; }
使用swagger調用,最後效果:code
後來查了一些資料,總結了一下:
https://darchuk.net/2019/05/31/asp-net-core-web-api-returning-a-filestream/