FileResult是一个基于文件的ActionResult,利用FileResult我们可以很容易地将从某个物理文件的内容响应给客户端。ASP.NET MVC定义了三个具体的FileResult,分别是FileContentResultFilePathResultFileStreamResult。在这篇文章中我们将探讨三种具体的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的TransmitFile实现了针对文件内容的响应。抽象类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 };
}
...
}

本文转载自蒋老师的了解ASP.NET MVC几种ActionResult的本质:FileResult

ASP.NET MVC 了解FileResult的本质的更多相关文章

  1. ASP.Net MVC 之FileResult

    FileResult是一个基于文件的ActionResult,利用FileResult我们可以很容易地将从某个物理文件的内容响应给客户端.ASP.NET MVC定义了三个具体的FileResult,分 ...

  2. Asp.Net MVC 使用FileResult导出Excel数据文件

    MVC实现Excel导出功能,今天来记录一下. 采取了最简单的方法.(转载)   用的是Html拼接成Table表格的方式,返回 FileResult 输出一个二进制的文件. 第一种:使用FileCo ...

  3. Asp.Net Mvc表单提交之List集合

    一.说明 1.Asp.Net Mvc中Action的参数可以自动接收和反序列化form表单的值, 2.对于name=value类型,只要Action参数的变量名和input的name相同就行,不区分大 ...

  4. 了解ASP.NET MVC几种ActionResult的本质:JavaScriptResult & JsonResult

    在之前的两篇文章(<EmptyResult & ContentResult>和<FileResult>)我们剖析了EmptyResult.ContentResult和F ...

  5. ASP.NET MVC不可或缺的部分——DI及其本质工作分析

    IoC框架最本质的东西:反射或者EMIT来实例化对象.然后我们可以加上缓存,或者一些策略来控制对象的生命周期,比如是否是单例对象还是每次都生成一个新的对象. DI实现其实很简单,首先设计类来实现接口, ...

  6. 了解ASP.NET MVC几种ActionResult的本质:HttpStatusCodeResult & RedirectResult/RedirectToRouteResult

    在本系列的最后一篇,我们来讨论最后三个ActionResult:HttpStatusCodeResult.RedirectResult和RedirectToRouteResult .第一个用于实现针对 ...

  7. 漫步ASP.NET MVC的处理管线

    ASP.NET MVC从诞生到现在已经好几个年头了,这个框架提供一种全新的开发模式,更符合web开发本质.你可以很好的使用以及个性化和扩展这个框架,但这需要你对它有足够的了解.这篇文章主要从整体角度总 ...

  8. 【读书笔记】Asp.Net MVC 上传图片到数据库(会的绕行)

    之前上传图片的做法都是上传到服务器上的文件夹中,再将url保存到数据库.其实在MVC中将图片上传到数据库很便捷的事情,而且不用去存url了.而且这种方式支持ie6(ie6不支持jquery自动提交fo ...

  9. [ASP.NET MVC 小牛之路]09 - Controller 和 Action (1)

    我们知道,在 MVC 中每个请求都会提交到 Controller 进行处理.Controller 是和请求密切相关的,它包含了对请求的逻辑处理,能对 Model 进行操作并选择 View 呈现给用户, ...

随机推荐

  1. Hadoop学习笔记—20.网站日志分析项目案例(一)项目介绍

    网站日志分析项目案例(一)项目介绍:当前页面 网站日志分析项目案例(二)数据清洗:http://www.cnblogs.com/edisonchou/p/4458219.html 网站日志分析项目案例 ...

  2. 表格搞定 Asp.net Web 状态管理

    最近在网上搜罗了 ASP.NET WEB 状态管理方面的一些内容,终于把这些内容整合总结了一下. 1. 希望自己通过整理,能够掌握一些,为自己投资. 2. 以便自己忘记,又要浪费时间搜罗. 3. 希望 ...

  3. ReactNative与NativeScript对比报告

    综合这段时间对ReactNative(下称RN)和NativeScript(下称NS)的简单学习了解,分别从不同方面分析对比二者的优缺点. 页面结构 NS一个页面的目录结构: RN的一个页面一般就是一 ...

  4. 谈谈UI架构设计的演化

    谈谈UI架构设计的演化 经典MVC 在1979年,经典MVC模式被提出. 在当时,人们一直试图将纯粹描述思维中的对象与跟计算机环境打交道的代码隔离开来,而Trygve Reenskaug在跟一些人的讨 ...

  5. Step by step Dynamics CRM 2013安装

    原创地址:http://www.cnblogs.com/jfzhu/p/4008391.html 转载请注明出处   SQL Server可以与CRM装在同一台计算机上,也可安装在不同的计算机上.演示 ...

  6. JavaScript学习笔记之Object

    对象(object)是JavaScript的核心概念,也是最重要的数据类型.JavaScript的所有数据都可以被视为对象. 简单说,所谓对象,就是一种无序的数据集合,由若干个“键值对”(key-va ...

  7. Atitit图像处理的用途

    Atitit图像处理的用途 1.1. 分类识别 (人脸检测,肤色识别,人类检测:1 1.2. 炫丽的动态按钮生成:色相旋转+自己的草书等图片合成,图片自动裁剪1 1.3. 集成调用自绘gui接口:识别 ...

  8. KnockoutJS 3.X API 第七章 其他技术(8) 异步错误处理

    注意:本文档适用于Knockout 3.4.0及更高版本. ko.onError Knockout包装内部异步调用,并在抛出原始错误之前查找可选的ko.onError回调以执行(如果遇到异常). 这使 ...

  9. 路由转发过程的IP及MAC地址变化

    A-----(B1-B2)-----(C1-C2)-------E就假设拓扑图是这个样子吧,B1和B2是路由器B上的两个接口,C1和C2是路由器C上的两个接口,A和E是PC,由主机A向主机E发送数据包 ...

  10. This build of Sublime Text 2 has expired

    使用一直很好的 sublime 2 最近一直提示: This build of Sublime Text 2 has expired, please update to a newer one fro ...