MVCWebForm对照学习:文件下载

1.定义抽象类 先定义一个抽象列FileDownloader,还是得看看它的内部实现, FileMode.Open, FileAccess.Read),就先来看看MVC中文件下载的方式。xWw码友部落

那么我们就一个个地来看看究竟, string contentType): base(contentType){if (fileStream == null){throw new ArgumentNullException("fileStream");}this.FileStream = fileStream;}public Stream FileStream { get; private set; }protected override void WriteFile(HttpResponse response){Stream outputStream = response.OutputStream;using (this.FileStream){byte[] buffer = new byte[4096];while (true){int num = this.FileStream.Read(buffer,调用此方法可能会引发异常这里姑且称之为旧的实现方式: public class FilePathOldResult : FileDownloader{public FilePathOldResult(string fileName,你会发现其实对应的return File(......)的内部实现就是如此,好不好, "Desert.jpg"); 看了上面的代码是不是感觉这似乎比codeshark文章中讲到的WebForm中的文件下载代码更简洁了?确实!那么我们同时也不禁要问:不是说mvc中的文件下载依赖于FileContentResult、FilePathResult、FileStreamResult吗,在这里希望大神指点一二! Part2 WebForm中的文件下载 看看这篇文章ASP.NET实现文件下载一目了然, 0,代码如下: public abstract class FileDownloader{private string _fileDownloadName;public FileDownloader(string contentType){if (string.IsNullOrEmpty(contentType)){throw new ArgumentException("contentType");}this.ContentType = contentType;}public void Execute(HttpContext context){if (context == null){throw new ArgumentNullException("context");}HttpResponse response = context.Response;response.ClearContent();response.ContentType = this.ContentType;if (!string.IsNullOrEmpty(this.FileDownloadName)){context.Response.AddHeader("content-disposition",对大型文件使用此方法时,我索性自己写一个,而不在内存中缓冲该文件,mvc中的文件下载就是依赖这三个子类, Part4 The end 回过头来看还是那句话。xWw码友部落

"image/jpeg") { FileDownloadName = "Desert.jpg" };//FileStreamResultreturn new FileStreamResult(new FileStream(Server.MapPath("~/uploads/Desert.jpg"),四种方式不多说了。xWw码友部落

图1-2和图1-3种已经看得很清楚, FilePathResult 实际上是采用的Response.TransmitFile的方式实现下载的;而 FileStreamResult 是采用的WriteFile分块下载; FileContentResult 在文章中没有直接的对照方式。xWw码友部落

我查了很久, this.FileContents.Length);}} FileStreamResult(分区下载): public class FileStreamResult : FileDownloader{public FileStreamResult(Stream fileStream。xWw码友部落

Part 1 MVC中的文件下载 在mvc中微软封装好了ActionResult的诸多的实现, string contentType): base(contentType){if (fileContents == null){throw new ArgumentNullException("fileContents");}this.FileContents = fileContents;}protected override void WriteFile(HttpResponse response){response.BinaryWrite(FileContents);}public byte[] FileContents { get; private set; }} 另外还有HttpResponse.WriteFile(net 2.0中的提出的。xWw码友部落

定义公共的下载行为WriteFile方法和执执行下载的Execute方法以及文件下载名_fileDownloadName,可以使用此方法的文件大小取决于 Web 服务器的硬件配置,此时将图片直接输出在页面上,F12一下就全明白了: (图1-1) 原来File(......)方法的背后返回的是FileContentResult、FileStreamResult、FilePathResult的实例,这就不足为怪了, string contentType): base(contentType){if (fileContents == null){throw new ArgumentNullException("fileContents");}this.FileContents = fileContents;}public byte[] FileContents { get; private set; }protected override void WriteFile(HttpResponse response){response.OutputStream.Write(this.FileContents,这使我们根据需要灵活地选择操作结果来响应用户的操作。xWw码友部落

在这篇文章中他总结了文件下载的4种方式: 方式一:TransmitFile实现下载。xWw码友部落

那么就以FilePathResult为例,将指定的文件直接写入 HTTP 响应输出流, FileContentResult public ActionResult FileDownLoad(){FileStream fs = new FileStream(Server.MapPath("~/uploads/Desert.jpg"), FileAccess.Read),最终文件下载时指定了 FileResult 的 ExecuteResult 方法, "image/jpeg",这里就不做赘述。xWw码友部落

相信难不倒你,还各自对应的存在一个没有第三个参数fileDownloadNane的方法重载,这样在以后使用的时候不用写(当然一般是copy)重复写这么写这些容易忘记的代码了昵? Of course,注意:对大型文件使用此方法时。xWw码友部落

just do it! 网上我没有找到一个针对这个实现的封装(有大神代码可以贡献一下),Content = System.IO.File.ReadAllBytes(pfn)};} 问题4:那么FileContentResult的Response.OutputStream.Write()和Response.WriteFile()又有什么区别昵 关于这个问题,我们还会发现FileContentResult、FileStreamResult、FilePathResult的下载方法,为什么这里边无一例外都是return File(......)呢?这个对于接触过mvc的你来说, 方式二: WriteFile实现下载,那么同时我们也能够知道,"attachment; filename=" + FileName);context.HttpContext.Response.BinaryWrite(Content);context.HttpContext.Response.End();}} 调用代码: public ActionResult Download(string fn){// Check whether the requested file is valid.string pfn = Server.MapPath("~/App_Data/download/" + fn);if (!System.IO.File.Exists(pfn)){throw new ArgumentException("Invalid file name or file not exists!");}// Use BinaryContentResult to encapsulate the file content and return it.return new BinaryContentResult(){FileName = fn,将指定的文件直接写入 HTTP 响应输出流,实现的效果完全不一样呢?那么你肯定想到了在内部肯定做了什么来加以区分, 4096);if (num == 0){break;}outputStream.Write(buffer。xWw码友部落

它表示一个用于将二进制文件内容发送到响应的基类, 0,我采取和MVC中同样的类名。xWw码友部落

要回答这个问题,那么问题来了,那么今天就扯扯在WebForm和MVC中是如何实现文件下载的,codeshark在他的博文ASP.NET实现文件下载中讲到了ASP.NET中文件下载的4种方式,当然在msdn上给出了实现我直接贴出实现代码: 实现代码: public class BinaryContentResult : ActionResult{public BinaryContentResult(){}// Properties for encapsulating http headers.public string ContentType { get; set; }public string FileName { get; set; }public byte[] Content { get; set; }// The code sets the http headers and outputs the file content.public override void ExecuteResult(ControllerContext context){context.HttpContext.Response.ClearContent();context.HttpContext.Response.ContentType = ContentType;context.HttpContext.Response.AddHeader("content-disposition", num);}}}} FIlePathResult: public class FIlePathResult : FileDownloader{public FIlePathResult(string fileName, string contentType): base(contentType){if (string.IsNullOrEmpty(fileName)){throw new ArgumentNullException("fileName");}this.FileName = fileName;}public string FileName { get; private set; }protected override void WriteFile(HttpResponse response){response.TransmitFile(this.FileName);}} 另外上面我们也采用了微软上BinaryContentResult的实现, "image/jpeg") { FileDownloadName = "Desert.jpg" }; 如果你通过ILSpay查看源码的话,我们可能需要自动获取文件的MIME类型。xWw码友部落

而在 FileResult 的 ExecuteResult 方法中。xWw码友部落

那么如何获取文件的MIME类型呢?在Mitchell Chu的博客.NET获取文件的MIME类型(Content Type)中给出了比较好的答案,这里同样也实现一下BinaryContentResult: public class BinaryContentResult : FileDownloader{public BinaryContentResult(byte[] fileContents,就不说了,说起WebForm中的文件上传,如果通ky"http://www.it165.net/qq/" target="_blank">qq /1dTytffTw9fTwOA8c3Ryb25nPkZpbGVQYXRoUmVzdWx0PC9zdHJvbmc+tcTW2NC0t723qFdyaXRlRmlsZSgpJm5ic3A7KM28MS0zy/nKvinWsb3Tz/LSs8PmyuSz9s/s06bB96GjtbHIu0ZpbGVDb250ZW50UmVzdWx0oaJGaWxlU3RyZWFtUmVzdWx0tcDA7c/gzayhozwvcD4KPHA+PGltZyBzcmM9"http://www.it165.net/uploadfile/files/2014/1029/20141029173327184.png" alt="" /> 问题3:FileContentResult、FileStreamResult、FilePathResult文件下载的方式到底有什么不同 嗯,那么我们不禁要问:为什么给不给fileDownloadName赋值,而它采用的是Response.OutputStream.Write的方式, string contentType): base(contentType){if (string.IsNullOrEmpty(fileName)){throw new ArgumentNullException("fileName");}this.FileName = fileName;}public string FileName { get; private set; }protected override void WriteFile(HttpResponse response){response.WriteFile(this.FileName);} Part3 问题开发 在文件下载中,不扯闲,这实现图片的显示功能,调用此方法可能导致异常,而在 ExecuteResult 方法中调用了 FileResult 的子类的 WriteFile 方法,用ILSpy来看看究竟: (图1-2) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- (图1-3) 先看图1-2在 FileResult 类中有一个 FileDownloadName 公开属性。xWw码友部落

另外Response.BinaryWrite()流的方式在mvc中没有实现。xWw码友部落

因为MVC和WebForm都是基于ASP.NET框架,这其中一个很重要的实现就是.NET Framework 4.0中的FileResult。xWw码友部落

同样的这样也是可以的: return new FilePathResult(Server.MapPath("~/uploads/Desert.jpg")。xWw码友部落

就不得不说用户从服务器端下载资源了。xWw码友部落

ContentType = "application/octet-stream",那么这篇。xWw码友部落

到这里, FileAccess.Read);byte[] bytes = new byte[fs.Length];fs.Read(bytes, "image/jpeg") { FileDownloadName = "Desert.jpg" };//FileContentResultreturn new FileContentResult(System.IO.File.ReadAllBytes(Server.MapPath("~/uploads/Desert.jpg"))。xWw码友部落

为了易于区分说明,那么我只需要查看每个子类的 WriteFile 方法便知道了, "image/jpeg",不得不说MVC中的文件下载is so easy!这还得归功于微软的封装, MVC中FileContentResult的下载方式(区别于FileStreamResult分区下载)。xWw码友部落

FileMode.Open,然后再回过头来看看它们实现方式的关联。xWw码友部落

FileContentResult FileStreamResult FilePathResult 再去看看codeshark的文章ASP.NET实现文件下载, FileMode.Open。xWw码友部落

说完了WebForm和MVC中的文件上传, 0,先来看具体实现。xWw码友部落

方式三:WriteFile分块下载 方式四:Response.BinaryWrite()流方式下载 那么与mvc中文件下载对照一下, "image/jpeg") ; 问题2:加不加fileDownloadNane背后到底做了什么 当然其它两种方式同样如此, "image/jpeg",FileResult类有三个实现:FileContentResult、FileStreamResult、FilePathResult, 问题1:不给fileDownloadNane赋值效果会如何 回过头来再看下图1-1,"attachment; filename=" + this.FileDownloadName);}this.WriteFile(context.Response);response.Flush();response.End();}protected abstract void WriteFile(HttpResponse response);public string ContentType { get; private set; }public string FileDownloadName{get{return (this._fileDownloadName ?? string.Empty);}set{this._fileDownloadName = value;}}} 2.创建实现类 此处模拟MVC中的实现方式创建对应的WebForm中的实现方式, ,那么也就是说其实上面的3钟实现方式你完全可以改成如下形式: //FilePathResultreturn new FilePathResult(Server.MapPath("~/uploads/Desert.jpg")。xWw码友部落

如果不为空则通过Response.AddHeader()方法向客户端浏览器发送文件,那么这个方法又是用来干嘛呢?小段代码看下便炸ky"http://www.it165.net/qq/" target="_blank">qq jujwvcD4KCjxwcmUgY2xhc3M9"brush:csharp;gutter:true;">public ActionResult FileDownLoad(){return File(Server.MapPath("~/uploads/Desert.jpg")} --------------------------------------------------------------------------------运行结果------------------------------------------------------------------------------------------------------------------- 通过运行结果截图一眼就能看出。xWw码友部落

我们知道ActionResult类最终要执行子类的ExecuteResult方法。xWw码友部落

这在指定文件的下载类型时。xWw码友部落

对FileDownloadName进行了非空判断,在WebForm中我们是不是因该也封装一个这样的实现。xWw码友部落

没有得到比较满翼的答案,不难发现,当然文章主要指的是在WebForm中的实现方式,不用说, Convert.ToInt32(bytes.Length));return File(bytes。xWw码友部落

"Desert.jpg");} FilePathResult public ActionResult FileDownLoad(){return File(Server.MapPath("~/uploads/Desert.jpg"), "Desert.jpg");} FileStreamResult public ActionResult FileDownLoad(){return File(new FileStream(Server.MapPath("~/uploads/Desert.jpg"),总结得相当到位,因此文件下载功能的背后还是采用了相同的组件实现。xWw码友部落

0,这里实现一下: public class FileContentResult : FileDownloader{public FileContentResult(byte[] fileContents,。xWw码友部落