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. 《JS修炼之道》—— 读后总结

    本篇是基于<JS修炼之道>的记录性与总结性的文章,这本书从多种框架的角度,讲述了JS开发中的一些实用技巧. 比如Prototype,JQuery,Mootools,YUI,Dojo,Ext ...

  2. 前端构建工具gulpjs的使用介绍及技巧

    gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取和操作数据,其速 ...

  3. 几个最常用的用来代替Div的HTML5元素

    虽说html5中大多数功能性的元素如<video><canvas><audio>等还得不到当前主流浏览器的支持(主要就是指IE浏览器了),但至少那些个与布局相关的元 ...

  4. KnockoutJS 3.X API 第六章 组件(1) 组件和自定义元素 - 概述

    Components (组件)是一个强大的,干净的方式组织您的UI代码,可重复使用的块. : -可以表示单独的控件/窗口小部件或应用程序的整个部分 -包含自己的视图,通常(但可选)自己的视图模型 -可 ...

  5. AngularJs入门之表单开发

    本文和大家分享的主要是前端开发中必备的AngularJs框架表单开发相关基础知识,希望对大家使用和学习AngularJs有所帮助. 1.简单的表单提交: 2.更多的表单元素: 3.初始化表单: 代码 ...

  6. VMware Workstation and Hyper-V are not compatible. 解决方案

    VMware 和 Hyper-V 不能共存问题报错如下:VMware Workstation and Hyper-V are notcompatible. Remove the Hyper-V rol ...

  7. dev c++ Boost库的安装

    dev c++ 的boost库的安装步骤 然后点击“check for updates”按钮 最后点击“Download selected”按钮,下载完成后安装.... 给dev添加boost库文件, ...

  8. EntityFramework之异步、事务及性能优化(九)

    前言 本文开始前我将循序渐进先了解下实现EF中的异步,并将重点主要是放在EF中的事务以及性能优化上,希望通过此文能够帮助到你. 异步 既然是异步我们就得知道我们知道在什么情况下需要使用异步编程,当等待 ...

  9. scikit-learn 支持向量机算法库使用小结

    之前通过一个系列对支持向量机(以下简称SVM)算法的原理做了一个总结,本文从实践的角度对scikit-learn SVM算法库的使用做一个小结.scikit-learn SVM算法库封装了libsvm ...

  10. 计时器StopWatch示例

    计时器 StopWatch stwatch = new StopWatch(getClass().getSimpleName()); try{ stwatch.start(joinPoint.getS ...