了解ASP.NET MVC几种ActionResult的本质:FileResult

简介:

FileResult是一个基于文件的ActionResult,利用FileResult我们可以很容易地将从某个物理文件的内容响应给客户端。ASP.NET MVC定义了三个具体的FileResult,分别是FileContentResult、FilePathResult和FileStreamResult。在这篇文章中我们将探讨三种具体的FileResult是如何将文件内容对请求进行响应的。[本文已经同步到《How ASP.NET MVC Works?》中]

目录
一、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是一个不错的选择。

三、FilePathResult

从名称可以看出,FilePathResult是一个根据物理文件路径创建FileResult。如下面的代码片断所示,表示响应文件的路径通过只读属性FileName表示,该属性在构造函数中被初始化。在实现的WriteFile方法中,FilePathResult直接将文件路径作为参数调用当前HttpResponse的TransmitFile实现了针对文件内容的响应。抽象类Controller同样定义了两个File方法重载来根据文件路径创建相应的FilePathResult。

   1: public class FilePathResult : FileResult
   2: {
   3:     public string FileName { get; }
   4:     public FilePathResult(string fileName, string contentType);
   5:  
   6:     protected override void WriteFile(HttpResponseBase response)
   7:     {
   8:         response.TransmitFile(this.FileName);
   9:     }    
  10: }
  11:  
  12: public abstract class Controller : ControllerBase, ...
  13: {
  14:     //其他成员
  15:     protected FilePathResult File(string fileName, string contentType);
  16:     protected virtual FilePathResult File(string fileName, string contentType, string fileDownloadName);
  17: }

四、FileStreamResult

FileStreamResult允许我们通过一个用于读取文件内容的流来创建FileResult。如下面的代码片断所示,读取文件流通过只读属性FileStream表示,该属性在构造函数中被初始化。在实现的WriteFile方法中,FileStreamResult通过指定的文件流读取文件内容,并最终调用当前HttpResponse的OutputStream属性的Write方法将读取的内容写入当前HTTP响应的输出流中。抽象类Controller中同样定义了两个File方法重载根据文件读取流创建相应的FileStreamResult。

   1: public class FileStreamResult : FileResult
   2: {
   3:     public Stream FileStream { get; }
   4:     public FileStreamResult(Stream fileStream, string contentType);    
   5:  
   6:     protected override void WriteFile(HttpResponseBase response)
   7:     {
   8:         Stream outputStream = response.OutputStream;
   9:         using (this.FileStream)
  10:         {
  11:             byte[] buffer = new byte[0x1000];
  12:             while (true)
  13:             {
  14:                 int count = this.FileStream.Read(buffer, 0, 0x1000);
  15:                 if (count == 0)
  16:                 {
  17:                     return;
  18:                 }
  19:                 outputStream.Write(buffer, 0, count);
  20:             }
  21:         }
  22:     }    
  23: }
  24:  
  25: public abstract class Controller : ControllerBase, ...
  26: {
  27:     //其他成员
  28:     protected FileStreamResult File(Stream fileStream, string contentType);
  29:     protected virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName);
  30: }

五、实例演示:通过FileResult发布图片

为了让读者对FileResult具有更加深刻地认识,我们通过一个实例来演示如何通过FileResult来对外发布图片。在通过Visual Studio的ASP.NET MVC项目模板创建的空Web应用中,我们在根目录下添加一个名为images的子目录来存放发布的.jpg图片,然后我们定义如下一个HomeController。

   1: public class HomeController : Controller
   2: {
   3:     public ActionResult Index()
   4:     {
   5:         return View();
   6:     }
   7:  
   8:     public ActionResult Image(string id)
   9:     {
  10:         string path = Server.MapPath("/images/" + id + ".jpg");
  11:         return File(path, "image/jpeg");
  12:     }
  13: }

图片的发布体现在Action方法Image上,表示图片ID的参数同时作为图片的文件名(不含扩展名)。在该方法中,我们根据图片ID解析出对应文件的路径后,直接调用File方法创建一个媒体类型为“image/jpeg”的FilePathResult。在Action方法Index中呈现的View定义如下,我们通过一个列表显示6张图片。基于图片的<img>元素的src属性指定的地址正是指向定义在HomeController的Action方法Image,指定的表示图片ID的参数分别是001、002、…、006。

   1: <html>
   2:     <head>
   3:         <title>Gallery</title>
   4:         <style type="text/css">
   5:             li{list-style-type:none; float:left; margin:10px 10px 0px 0px;}
   6:             img{width:100px; height:100px;}
   7:         </style>
   8:     </head>
   9:     <body>
  10:         <ul>
  11:             <li><img alt="001" src="@Url.Action("Image", new { id = "001" })"/></li>
  12:             <li><img alt="002" src="@Url.Action("Image", new { id = "002" })"/></li>
  13:             <li><img alt="003" src="@Url.Action("Image", new { id = "003" })"/></li>
  14:             <li><img alt="004" src="@Url.Action("Image", new { id = "004" })"/></li>
  15:             <li><img alt="005" src="@Url.Action("Image", new { id = "005" })"/></li>
  16:             <li><img alt="006" src="@Url.Action("Image", new { id = "006" })"/></li>
  17:  
  18:         </ul>
  19:     </body>
  20: </html>

我们将6张.jpg图片存放到/imges目录下,并分别命名为001、002、…、006。直接运行程序之后这6张图片会以如下图所示的效果显示在浏览器上。

image

了解ASP.NET MVC几种ActionResult的本质:EmptyResult & ContentResult
了解ASP.NET MVC几种ActionResult的本质:FileResult
了解ASP.NET MVC几种ActionResult的本质:JavaScriptResult & JsonResult
了解ASP.NET MVC几种ActionResult的本质:HttpStatusCodeResult & RedirectResult/RedirectToRouteResult


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
38 0
|
29天前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
28 0
|
29天前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
5 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
95 5
|
3月前
|
XML 前端开发 定位技术
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
25 0
|
3月前
|
前端开发
.net core mvc获取IP地址和IP所在地(其实是百度的)
.net core mvc获取IP地址和IP所在地(其实是百度的)
123 0
|
5月前
|
开发框架 自然语言处理 前端开发
基于ASP.NET MVC开发的、开源的个人博客系统
基于ASP.NET MVC开发的、开源的个人博客系统
51 0
|
8月前
|
SQL 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(完:内附源码)
经过一段时间的准备,【ASP.NET Core MVC开发实战之商城系统】已经完成,目前代码已开发完成,先将全部内容整理分享,如有不足之处,还请指正。
106 0
|
8月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
114 0
|
9月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
67 0