浅谈ActionResult之FileResult
FileResult是一个基于文件的ActionResult,利用FileResult,我们可以很容易的将某个物理文件的内容响应给客户端,ASP.NET MVC定义了三个具体的FileResult,分别是 FileContentResult、FilePathResult、FileStreamResult。在这篇文章中,我们来探讨一下三种具体的FileResult是如何将文件内容对请求进行响应的。
一、FileResult
如下面的代码片段所示,FileResult具有一个表示媒体类型的只读属性ContentType,该属性在构造函数中被初始化。当我们基于某个物理文件创建响应的FileResult对象的时候,应该根据文件的类型指定媒体类型,比如说,目标文件是一个.JPG图片,那么对应的媒体类型就应该是“image/jpeg”,对于一个.pdf文件,则采用“application/pdf”。
public abstract class FileResult : ActionResult
{
private string _fileDownloadName; protected FileResult(string contentType)
{
if (string.IsNullOrEmpty(contentType))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentType");
}
this.ContentType = contentType;
} public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = this.ContentType;
if (!string.IsNullOrEmpty(this.FileDownloadName))
{
string headerValue = ContentDispositionUtil.GetHeaderValue(this.FileDownloadName);
context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
}
this.WriteFile(response);
} protected abstract void WriteFile(HttpResponseBase response); public string ContentType { get; private set; } public string FileDownloadName
{
get
{
return (this._fileDownloadName ?? string.Empty);
}
set
{
this._fileDownloadName = value;
}
} internal static class ContentDispositionUtil
{
private const string HexDigits = "0123456789ABCDEF"; private static void AddByteToStringBuilder(byte b, StringBuilder builder)
{
builder.Append('%');
int num = b;
AddHexDigitToStringBuilder(num >> , builder);
AddHexDigitToStringBuilder(num % 0x10, builder);
} private static void AddHexDigitToStringBuilder(int digit, StringBuilder builder)
{
builder.Append("0123456789ABCDEF"[digit]);
} private static string CreateRfc2231HeaderValue(string filename)
{
StringBuilder builder = new StringBuilder("attachment; filename*=UTF-8''");
foreach (byte num in Encoding.UTF8.GetBytes(filename))
{
if (IsByteValidHeaderValueCharacter(num))
{
builder.Append((char) num);
}
else
{
AddByteToStringBuilder(num, builder);
}
}
return builder.ToString();
} public static string GetHeaderValue(string fileName)
{
foreach (char ch in fileName)
{
if (ch > '\x007f')
{
return CreateRfc2231HeaderValue(fileName);
}
}
ContentDisposition disposition = new ContentDisposition {
FileName = fileName
};
return disposition.ToString();
} private static bool IsByteValidHeaderValueCharacter(byte b)
{
if ((0x30 <= b) && (b <= 0x39))
{
return true;
}
if ((0x61 <= b) && (b <= 0x7a))
{
return true;
}
if ((0x41 <= b) && (b <= ))
{
return true;
}
switch (b)
{
case 0x3a:
case 0x5f:
case 0x7e:
case 0x24:
case 0x26:
case 0x21:
case 0x2b:
case 0x2d:
case 0x2e:
return true;
}
return false;
}
}
}
针对文件的响应具有两种形式,内联(Inline)和附件(Attachment)。一般来说,前者会利用浏览器直接打开响应文件,而后者则会以独立的文件下载到客户端。对于后者,我们一般会为下载的文件指定一个文件名,这个文件名可以通过FileResult的FileDownloadName属性来指定。文件响应在默认情况下采用内联方式,如果需要采用附件的形式,需要为响应创建一个名为Content-Disposition的报头,该报头值的格式为“attachment;filename={FileDownloadName}”。
FileResult仅仅是一个抽象类,文件内容的输出实现在抽象方法WriteFile中,该方法会在重写的ExecuteResult方法中调用。如果FileDownloadName属性不为空,意味着会采用附件的形式进行文件响应,FileResult会在重写的ExecuteResult方法中进行Content-Disposition响应报头的设置。如下面的代码片段,基本上体现了ExecuteResult方法在FileResult中的体现。
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = this.ContentType;
if (!string.IsNullOrEmpty(this.FileDownloadName))
{
string headerValue = ContentDispositionUtil.GetHeaderValue(this.FileDownloadName);
context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
}
this.WriteFile(response);
}
ASP.NET MVC定义了三个具体的FileResult,分别是FileContentResult、FilePathResult、FileStreamResult。接下来我们对他们进行单独介绍。
二、FileContentResult
FileContentResult是针对文件内容创建的FileResult。如下面的代码片段所示,FileContentResult具有一个字节数组类型的只读属性FileContents表示响应文件的内容,该属性在构造函数中指定。FileContentResult针对文件内容的响应实现也很简单,从如下示的WriteFile方法定义可以看出,它只是调用当前HttpResponse的OutputStream属性的Write方法直接将表示文件内容的字节数组写入响应输出流。
public class FileContentResult : FileResult
{
public FileContentResult(byte[] fileContents, string contentType) : base(contentType)
{
if (fileContents == null)
{
throw new ArgumentNullException("fileContents");
}
this.FileContents = fileContents;
} protected override void WriteFile(HttpResponseBase response)
{
response.OutputStream.Write(this.FileContents, , this.FileContents.Length);
} public byte[] FileContents { get; private set; }
}
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer
{
protected internal FileContentResult File(byte[] fileContents, string contentType)
{
return this.File(fileContents, contentType, null);
}
protected internal virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName)
{
return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
}
}
抽象类Controller中定义了如上两个File重载根据指定的字节数组、媒体类型和下载文件名(可选)生成相应的FileContentResult。由于FileContentResult是根据字节数组创建的,当我们需要动态生成响应文件内容(而不是从物理文件中读取)时,FileContentResult是一个不错的选择。
三、FilePathResult
从名称可以看出,FilePathResult是一个根据物理文件路径创建FileResult。如下面的代码片段所示,表示响应文件的路径通过只读属性FileName表示,该属性在构造函数中被初始化。在实现的WriteFile方法中,FilePathResult直接将文件路径作为参数调用当前HttpResponse的TransmiteFile实现了针对文件内容的响应。抽象类Controller同样定义了两个File方法重载来根据文件路径创建相应的FilePathResult。
public class FilePathResult : FileResult
{
public FilePathResult(string fileName, string contentType) : base(contentType)
{
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "fileName");
}
this.FileName = fileName;
} protected override void WriteFile(HttpResponseBase response)
{
response.TransmitFile(this.FileName);
} public string FileName { get; private set; }
}
public abstract class Controller : ControllerBase,...
{
protected internal FilePathResult File(string fileName, string contentType)
{
return this.File(fileName, contentType, null);
}
protected internal virtual FilePathResult File(string fileName, string contentType, string fileDownloadName)
{
return new FilePathResult(fileName, contentType) { FileDownloadName = fileDownloadName };
}
.....
}
四、FileStreamResult
FileStreamResult允许我们通过一个用于读取文件内容的流来创建FileResult。如下面的代码片段所示,读取文件流通过只读属性FileStream表示,该属性在构造函数中被初始化。在实现的WriteFile方法中,FileStreamResult通过指定的文件流读取文件内容,并最终调用当前HttpResponse的OutputStream属性和Write方法将读取的内容写入当前Http相应的输出流中。抽象类Controller中同样定义了两个File方法重载根据文件杜宇流创建相应的FileStreamResult。
public class FileStreamResult : FileResult
{
private const int BufferSize = 0x1000; public FileStreamResult(Stream fileStream, string contentType) : base(contentType)
{
if (fileStream == null)
{
throw new ArgumentNullException("fileStream");
}
this.FileStream = fileStream;
} protected override void WriteFile(HttpResponseBase response)
{
Stream outputStream = response.OutputStream;
using (this.FileStream)
{
byte[] buffer = new byte[0x1000];
while (true)
{
int count = this.FileStream.Read(buffer, , 0x1000);
if (count == )
{
return;
}
outputStream.Write(buffer, , count);
}
}
} public Stream FileStream { get; private set; }
}
public abstract class Controller : ControllerBase, ...
{
protected internal FileStreamResult File(Stream fileStream, string contentType)
{
return this.File(fileStream, contentType, null);
}
protected internal virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName)
{
return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
}
...
}
以上便是FileResult的三个子类。好了,关于FileResult的接受就到这里。
浅谈ActionResult之FileResult的更多相关文章
- 【ASP.NET MVC系列】浅谈ASP.NET MVC八大类扩展(上篇)
lASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操 ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 控制器
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- 浅谈SQL注入风险 - 一个Login拿下Server(转)
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- 【ASP.NET MVC系列】浅谈表单和HTML辅助方法
[01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作篇)(下) [04]浅谈ASP. ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC资源过滤和授权
最近比较忙,博客很久没更新了,很多博友问何时更新博文,因此,今天就花了点时间,写了本篇文章,但愿大家喜欢. 本篇文章不适合初学者,需要对ASP.NET MVC具有一定基础. 本篇文章主要从ASP.NE ...
- 【ASP.NET MVC系列】浅谈jqGrid 在ASP.NET MVC中增删改查
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图与控制器传递数据
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
随机推荐
- Spring Boot 集成 Seata 解决分布式事务问题
seata 简介 Seata 是 阿里巴巴2019年开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务.在 Seata 开源之前,Seata 对应的内部版本在阿里内部一 ...
- 云资源中的低成本战斗机——竞价实例,AWS、阿里云等六家云厂商完全用户使用指南
云端资源价格 预留实例:长期持有,批发路线,价格最便宜. 按需实例:即买即用,零售路线,价格最贵. 这两种资源,基于不同区域/价格的六家云厂商价格对比,连同原始数据文档我们已经打包成了一份电子文档,有 ...
- 图解kubernetes调度器预选设计实现学习
Scheduler中在进行node选举的时候会首先进行一轮预选流程,即从当前集群中选择一批node节点,本文主要分析k8s在预选流程上一些优秀的筛选设计思想,欢迎大佬们指正 1. 基础设计 1.1 预 ...
- NetCore下的log4
https://www.cnblogs.com/zhangxiaoyong/p/9463791.html 这一篇也不错 .NET常用的日志组件有NLog.Log4net等,.NET CORE下微软也自 ...
- redis 5种类型
redis可以不严谨的看成: redis: { name: value, name: value, } value的数据类型: 1.字典 2.列表 3.字符串 4.集合 5.有序集合 注意: redi ...
- ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'问题的解决
.与limit相关的sql语句作为临时表 select * from 临时表 limit ) as B 缺点:只能查临时表的数据 .可以查原表的数据 select * from test where ...
- mysql 执行计划和慢日志记录
一.执行计划 1.作用预估sql语句执行的时间,一般准确2.格式: explain sql语句3.type类型的快慢(all最慢,const最快)all < index < range & ...
- B-Tree 和 B+Tree 结构及应用,InnoDB 引擎, MyISAM 引擎
1.什么是B-Tree 和 B+Tree,他们是做什么用的? B-Tree是为了磁盘或其它存储设备而设计的一种多叉平衡查找树,B-Tree 和 B+Tree 广泛应用于文件存储系统以及数据库系统中. ...
- 在动作方法中生成输出URL (Generating Outgoing URLs in Action Methods) |
- HGE_improve 0.1发布
HGE_improve 0.1发布 写了1个月了,虽然还有很多很多缺陷,但丑姑娘也是要见公婆的. 主要修改如下: 1.全UNICODE化 2.增加切片动画 3.增加骨骼动画 4.增加MyGUI接口 5 ...