FileResult是一個基於文件的ActionResult,利用FileResult我們可以很容易地將從某個物理文件的內容響應給客戶端。ASP.NET MVC定義了三個具體的FileResult,分別是FileContentResult、FilePathResult和FileStreamResult。在這篇文章中我們將探討三種具體的FileResult是如何將文件內容對請求進行響應的。
一、FileResult
如下面的代碼片斷所示,FileResult具有一個表示媒體類型的只讀屬性ContentType,該屬性在構造函數中被初始化。當我們基於某個物理文件創建相應的FileResult對象的時候應該根據文件的類型指定媒體類型,比如說目標文件是一個.jpg圖片,那麼對應的媒體類型為“image/jpeg”,對於一個.pdf文件,則采用“application/pdf”。
1: public abstract class FileResult : ActionResult
2: {
3: protected FileResult(string contentType);
4: public override void ExecuteResult(ControllerContext context);
5: protected abstract void WriteFile(HttpResponseBase response);
6:
7: public string ContentType { get; }
8: public string FileDownloadName { get; set; }
9: }
針對文件的響應具有兩種形式,即內聯(Inline)和附件(Attachment)。一般來說,前者會利用浏覽器直接打開響應的文件,而後者會以獨立的文件下載到客戶端。對於後者,我們一般會為下載的文件指定一個文件名,這個文件名可以通過FileResult的FileDownloadName屬性來指定。文件響應在默認情況下采用內聯的方式,如果需要采用附件的形式,需要為響應創建一個名稱為Content-Disposition的報頭,該報頭值的格式為“attachment; filename={ FileDownloadName }”。
FileResult僅僅是一個抽象類,文件內容的輸出實現在抽象方法WriteFile中,該方法會在重寫的ExecuteResult方法中調用。如果FileDownloadName屬性不為空,意味著會采用附件的形式進行文件響應,FileResult會在重寫的ExecuteResult方法中進行Content-Disposition響應報頭的設置。如下面的代碼片斷基本上體現了ExecuteResult方法在FileResult中的實現。
1: public abstract class FileResult : ActionResult
2: {
3: //其他成員
4: public override void ExecuteResult(ControllerContext context)
5: {
6: HttpResponseBase response = context.HttpContext.Response;
7: response.ContentType = this.ContentType;
8: if (!string.IsNullOrEmpty(this.FileDownloadName))
9: {
10: //生成Content-Disposition響應報頭值
11: string headerValue = ContentDispositionUtil.GetHeaderValue(this.FileDownloadName);
12: context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
13: }
14: this.WriteFile(response);
15: }
16: }
ASP.NET MVC定義了三個具體的FileResult,分別是FileContentResult、FilePathResult和FileStreamResult,接下來我們對它們進行單獨介紹。
二、FileContentResult
FileContentResult是針對文件內容創建的FileResult。如下面的代碼片斷所示,FileContentResult具有一個字節數組類型的只讀屬性FileContents表示響應文件的內容,該屬性在構造函數中指定。FileContentResult針對文件內容的響應實現也很簡單,從如下所示的WriteFile方法定義可以看出,它只是調用當前HttpResponse的OutputStream屬性的Write方法直接將表示文件內容的字節數組寫入響應輸出流。
1: public class FileContentResult : FileResult
2: {
3: public byte[] FileContents { get; }
4: public FileContentResult(byte[] fileContents, string contentType) ;
5:
6: protected override void WriteFile(HttpResponseBase response)
7: {
8: response.OutputStream.Write(this.FileContents, 0, this.FileContents.Length);
9: }
10: }
11:
12: public abstract class Controller : ControllerBase, ...
13: {
14: // 其他成員
15: protected FileContentResult File(byte[] fileContents, string contentType);
16: protected virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName);
17: }
抽象類Controller中定義了如上兩個File重載根據指定的字節數組、媒體類型和下載文件名(可選)生成相應的FileContentResult。由於FileContentResult是根據字節數組創建的,當我們需要動態生成響應文件內容(而不是從物理文件中讀取)時,FileContentResult是一個不錯的選擇。