MVC&WebForm对照学习:文件上传(以图片为例)

在web应用中,文件上传是个很普遍的功能,那么今天就来小结一下asp.net中文件上传的方式。首先我们快速来回忆一下WebForm中的文件上传的方法。

Part 1 WebForm中的文件上传

 FileUpload服务器控件

aspx:

<div><asp:Image ImageUrl="~/uploads/1.jpg" ID="img2" runat="server" Width="150px" Height="150px" /><asp:FileUpload runat="server" ID="fupImage" /><input type="button" value="上传" id="btnSubmit" runat="server" onserverclick="btnSubmit_ServerClick" />
</div>

aspx.cs:

protected void btnSubmit_ServerClick(object sender, EventArgs e)
{if (fupImage.HasFile){Regex regex = new Regex(@".(?i:jpg|jpeg|gif|png)$");if (regex.IsMatch(Path.GetExtension(fupImage.FileName))){string path = AppDomain.CurrentDomain.BaseDirectory + "uploads";if (!Directory.Exists(path))Directory.CreateDirectory(path);string filePath = fupImage.FileName;  //此处需要处理同名文件
            fupImage.SaveAs(Path.Combine(path, filePath));img2.ImageUrl = "~/uploads/" + filePath;}}
}

运行结果:

Note:如果image是普通的html服务器控件,那么后台赋值就要这样:

img1.Src = "~/uploads/" + filePath;

 Html服务器控件

aspx:

<div><asp:Image ImageUrl="~/uploads/1.jpg" ID="img2" runat="server" Width="150px" Height="150px" /><input type="file" runat="server" id="fileimg" /><input type="button" value="上传" id="btnSubmit" runat="server" onserverclick="btnSubmit_ServerClick" />
</div>

aspx.cs:

if (fileimg.PostedFile.ContentLength > 0)
{string fileName = Path.GetFileName(fileimg.PostedFile.FileName);Regex regex = new Regex(@".(?i:jpg|jpeg|gif|png)$");if (regex.IsMatch(Path.GetExtension(fileName))){string path = AppDomain.CurrentDomain.BaseDirectory + "uploads";if (!Directory.Exists(path))Directory.CreateDirectory(path);fileimg.PostedFile.SaveAs(Path.Combine(path, fileName));img2.ImageUrl = "~/uploads/" + fileName;}
}

运行也能实现同样的效果。

 普通的Html标签

aspx:

<div><asp:Image ImageUrl="~/uploads/1.jpg" ID="img2" runat="server" Width="150px" Height="150px" /><input type="file" runat="server" id="fileimage"/><input type="button" value="上传" id="btnSubmit" runat="server" onserverclick="btnSubmit_ServerClick" />
</div>

aspx.cs

if (Request.Files["fileimage"].HasFile())
{string fileName = Path.GetFileName(Request.Files["fileimage"].FileName);  //此处位需要处理同名文件Regex regex = new Regex(@".(?i:jpg|jpeg|gif|png)$");if (regex.IsMatch(Path.GetExtension(fileName))){string path = AppDomain.CurrentDomain.BaseDirectory + "uploads";if (!Directory.Exists(path))Directory.CreateDirectory(path);Request.Files["fileimage"].SaveAs(Path.Combine(path, fileName));img2.ImageUrl = "~/uploads/" + fileName;}
}

Note:以上仅仅为了说明问题,故省去了对文件size的判断。

回过头来在看看,我们会发现如下关系:

---------------------------------------------------------------------------------------------

再来看看它们最终save的方法:

---------------------------html服务器控件------------------------------------------

---------------------------html标签------------------------------------------------

Note:由于服务器控件FileUpload,我暂时还没办法通过反序列化查看到内部细节,故缺少图片。

通过上面三种不同的标签的实现方式,可以看出基本上都是殊途同归。因为我们知道服务器控件只是封装了某些东西,(虽然通过反编译有些代码还是查看不到)我们完全可以揣测,这种实现其实就是最终第三种方式来实现的,使我们操作起来更加方便而已,它最终还是要转换成普通的html标签。因此服务器控件的性能相比较而言有所损失。但是由于它会根据不同的浏览器生成一些样式和脚本,因此兼容性会较好。那么抛开兼容性不说,既然它们最终的实现方式是一样的(HttpPostedFile对象),那么我们完全可以抽象出一个共通的方法来实现,以省去每次使用它们的时候要写不同的处理方式。一下以html控件为例:

(注1)

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public static void Upload(string filePath){    var request = System.Web.HttpContext.Current.Request;    foreach (string upload in request.Files)    {        HttpPostedFile hp = request.Files[upload];        if (hp.HasFile())        {            CreateFolderIfNeeded(filePath);            string fileName = Path.GetFileName(hp.FileName);  //此处位需要处理同名文件            hp.SaveAs(Path.Combine(filePath, fileName));        }    }}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

private static void CreateFolderIfNeeded(string path) {if (!Directory.Exists(path)) {try {Directory.CreateDirectory(path);}catch (Exception) {/*TODO: You must process this exception.*///throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));}}
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public static class HttpPostFileExtensions {   //扩展方法必须在顶级类中定义public static bool HasFile(this HttpPostedFile file) {return (file != null && file.ContentLength > 0) ? true : false;}
}

注1:特别注意的是由于Request.Files是名称值对的集合,而名称正是html标签的name属性的值,故使用普通的html控件的时候需要给file标签加上name属性,否则后台无法获取到它的值。

Part 2 MVC中的文件上传

如果习惯了使用WebForm服务器控件开发,那么初次接触MVC(本文以razor为例),你会发现这些服务器控件已经派不上用场了,就以文件上传为例,我们没办法像以前那样使用FileUpload愉快地拖曳来实现文件上传了。当然了所有的ASP.NET服务器控件也好,html服务器控件也好包括MVC的Htmlhelper,这些最终都要生成普通的html标签。而且MVC和WebForm都是基于ASP.NET平台的,那么从这2个点来说,我们在上文中最后提供的一个抽象封装(当然这只是一个简单的demo,它不能满足所有的实际开发中的变化了的需求)方法按道理来说也适用于MVC,那么究竟是不是这样呢?小段代码为证:

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "form1", enctype = "multipart/form-data" }))
{<img src="/uploads/1.jpg" alt="暂无图片" id="img1" style="width:150px;height:150px;" /><input type='file' name='file' id='file' /><input type="button" value="上传" id="btnSubnit" />
}
<script src="~/Scripts/jquery-1.4.1.min.js"></script>
<script src="~/Scripts/jquery-form.js"></script>
<script type="text/javascript">$(document).ready(function () {$("#file").bind("change", function () {$("#form1").ajaxSubmit({success: function (data) {$("#img1").attr("src", data.filePath);}});});});
</script>

---------------------------------------------------------------------请允许我丑陋的展现方式-------------------------------------------------------------------------------------

[HttpPost]
public ActionResult Index(HttpPostedFileBase file/*这里的参数暂时无用*/)
{string path = AppDomain.CurrentDomain.BaseDirectory + "uploads";UpLoadFileHelper.Upload(path);var filePath = "/uploads/" + Path.GetFileName(Request.Files["file"].FileName);return Json(new { filePath = filePath });
}

---------------------------------------------------------------------运行结果---------------------------------------------------------------------------------------------------

Note:以上使用了UpLoadFileHelper.Upload只是为了说明问题。实际开发中随着页面需求的变化,这个实现也要进行重构,也恳请博友能够提供完美的方案。

在WebForm中有HttpPostedFile对象,同样的在MVC中也有HttpPostedFileBase(我不知道微软是不是有意在名字上加以区分)。其实它们反应到上下文中是一样的。像这样的情况还有很多,比方说细心的你一定会发现,在Controller中取到的HttpContext是HttpContextBase而在WebForm中是HttpContext。虽然他们是两个不同的对象,但是内部实现是一样的(当然我没有查阅所有的这些类似的对象,也不保证所有的这些类似对象都是同样的实现)。那么我们就使用HttpPostedFileBase来看看MVC中如何实现单个文件的上传的:

[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{if (null != file && file.ContentLength>0){string path = AppDomain.CurrentDomain.BaseDirectory + "uploads";if (!Directory.Exists(path)){Directory.CreateDirectory(path);}string fileName = string.Empty;fileName = Path.GetFileName(file.FileName);file.SaveAs(Path.Combine(path, fileName));return Json(new { filePath = "/uploads/" + fileName, code = 1 });}return Json(new { filePath = "请选择需要上传的文件", code = 0 });
}

同样也能实现同样的效果。

Note:由于HttpPostedFileBase是从Request.Files["name"]得到的,因此Action中HttpPostedFileBase的变量名必须保持和View中file标签的name属性值一致。

Part 3 问题开发

  关于input type="file"的style

众所周知,file input标签在不同的浏览器中会展现不同的样式,在实际开发中,针对这个也有很多很好的解决方案,这个可以baidu或者google(说道此,满眼是泪,希望博友可以提供海量无需FQ即可访问google的网址,在此不胜感激!!!)。我在这里引用WebMagazine网站一个解决方案,只要代码如下:

---------------------------------------------------------------------HTML标签---------------------------------------------------------------------------------------------------

<div class="file-wrapper"><input type="file" /><span class="button">Choose a file</span>
</div>

---------------------------------------------------------------------jQuery-----------------------------------------------------------------------------------------------------

<script src="jquery.js"></script>
<script type="text/javascript">var SITE = SITE || {};SITE.fileInputs = function () {var $this = $(this),$val = $this.val(),valArray = $val.split('\\'),newVal = valArray[valArray.length - 1],$button = $this.siblings('.button'),$fakeFile = $this.siblings('.file-holder');if (newVal !== '') {$button.text('File Chosen');if ($fakeFile.length === 0) {$button.after('<span class="file-holder">' + newVal + '</span>');} else {$fakeFile.text(newVal);}}};$(document).ready(function () {$('.file-wrapper input[type=file]').bind('change focus click', SITE.fileInputs);});
</script>

---------------------------------------------------------------------Css---------------------------------------------------------------------------------------------------------

<style type="text/css">.file-wrapper {position: relative;display: inline-block;overflow: hidden;cursor: pointer;}.file-wrapper input {position: absolute;top: 0;right: 0;filter: alpha(opacity=1);opacity: 0.01;-moz-opacity: 0.01;cursor: pointer;}.file-wrapper .button {color: #fff;background: #117300;padding: 4px 18px;margin-right: 5px;border-radius: 5px;-moz-border-radius: 5px;-webkit-border-radius: 5px;display: inline-block;font-weight: bold;cursor: pointer;}.file-holder {color: #000;}
</style>

完整代码下载

  关于ASP.NET中input type="file"单次请求上传文件超过默认(ASP.NET为4M,IIS7为30M)时处理异常

在ASP.NET Web开发中,这也不是什么新问题,在这里我想既然说到了文件上传,那么不得不在老调重弹一下,而且网上虽说对于这个问题早有定论,但是还是会看到不少对ASP.NET和IIS默认限制大小的具体说法有些混乱。测试环境为iis7+asp.net 4.0。

 Situation 1:不改默认配置的情况下使用FileUpload上传一个4.69M的文件:

  Situation 2:不改默认配置的情况下使用FileUpload上传一个40M的文件:

另外更糟糕的是甚至会出现这种情况:

从不同的错误页面不难看出,asp.net 默认限制上传大小不超过4M,运行时间不超过90s(因此会出现第三种错误的页面),iis7环境下为30M,超过默认设置,IIS会认为用户是在恶意攻击,因此会拒绝请求。当然微软考虑到上传到文件的需求,因此这个问题是可以通过配置解决的。那么针对它们的解决办法:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------    

Note1:关于此问题的更详细的解决办法,可以参考Large File Upload in IIS。

Note2:不仅如此ASP.NET和IIS对其它的诸如QueryString、Url也都有限制。比方说,当文本框输入的字节超过2048个字节的时候同样会引发异常。我想之所以网上关于这个问题的解读会出现偏差可能是这于这两者没有仔细查看的缘故吧。我想如果是这样的话,那么我们就需要仔细看看这两个配置借点的相信阐述了:httpRuntime、requestFiltering。

Part 4 拓展

另外说到这么多file的问题,其实我们常常看到有些网站会有上传进度条、图片剪切、拖曳上传、异步上传等,而如果要在file基础上实现这个,还是有点麻烦的。我们使用第三方组件来实现。这个在百度上也能找到能多既有的方案。我推荐一个能够实现多文件和进度条上传的组件jQuery Multiple File Upload with Progress bar Tutorial。文件上传的jQuery File Upload Demo以及jQuery File Upload。唉,好的插件确实是太多了,看得我眼花缭乱,不禁要感叹,再也不用担心文件上传了。根据自己的需要选择吧。

Part 5 参阅链接

http://www.codeproject.com/Articles/442515/Uploading-and-returning-files-in-ASP-NET-MVC

http://weblogs.asp.net/bryansampica/AsyncMVCFileUpload

http://ajaxuploader.com/large-file-upload-iis-asp-net.htm

http://ajaxuploader.com/large-file-upload-iis-asp-net.htm

http://msdn.microsoft.com/zh-cn/library/ms689462.aspx

Part 6 The end

注:由于个人技术有限,对某些概念的理解可能会存在偏差,如果你发现本文存在什么bug,请指正。谢谢!

完。

posted on 2014-10-19 23:23 深谷&幽兰 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/fengchengjushi/p/fileupload.html

MVCWebForm对照学习:文件上传(以图片为例)相关推荐

  1. idea使用Commons-FileUpload组建实现文件上传-以图片为例

    转载两篇文章介绍: https://blog.csdn.net/xiaotaozisha/article/details/79883043 https://blog.csdn.net/wzy18210 ...

  2. 【SpringBoot学习】5、SpringBoot 实现文件上传,图片上传并显示功能

    SpringBoot 实现文件上传,图片上传并显示功能 我先看一下<颈椎病康复指南>再给大家说怎么实现的这两个功能,毕竟只是一个新手,解决这种复杂点的问题(相对而言),还是需要花费大量时间 ...

  3. 轻松搞定阿里OSS文件上传和图片下载

    轻松搞定阿里OSS文件上传和图片下载 目录 1. 阿里云oss账号准备   1.1 注册阿里云账号,并开通OSS存储服务   1.2 创建RAM子用户并使用子账户的AccessKeyId和Access ...

  4. 文件上传之图片上传题目

    [A]文件上传之图片上传题目 Give me your photo PLZ 提示 我好想看一些好康的图片呜呜 题目 .htaccess是Apache的又一特色.一般来说,配置文件的作用范围都是全局的, ...

  5. 渗透学习-文件上传篇-基础知识部分(持续更新中)

    提示:仅供进行学习使用,请勿做出非法的行为.如若由任何违法行为,将依据法律法规进行严惩!!! 文章目录 前言 一.文件上传漏洞简要阐述 文件上传是什么? 为什么会产生文件上传漏洞?及其可能一哪些危害? ...

  6. 农夫安全学习——文件上传漏洞

    学习自农夫安全A14 文件上传漏洞 定义 成因 危害 攻击流程 防护和绕过 解析漏洞 问题和思考 后记 定义 由于程序员在对用户文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型或者处理缺 ...

  7. php多图片上传程序,php多文件上传 多图片上传程序代码

    多文件上传其实就包括了图片及各种文件了,下面介绍的是一款PHP多文件上传类,一共两个文件,upp.php 和 uploadFile.php,upp.php,这是前台所显示的表单文件了,默认的是四个上传 ...

  8. SpringMVC学习--文件上传

    简介 文件上传是web开发中常见的需求之一,springMVC将文件上传进行了集成,可以方便快捷的进行开发. springmvc中对多部件类型解析 在 页面form中提交enctype="m ...

  9. ASP.NET2.0文件上传以及图片处理总结篇 [转]

    1.最简单的单文件上传(没花头) 2.多文件上传 3.客户端检查上传文件类型(以上传图片为例) 4.服务器端检查上传文件类型(以上传图片为例) 5.服务器端检查上传文件类型(可以检测真正文件名) 6. ...

最新文章

  1. Endnote生成的中英文混排参考文献中“等”与“et al”的处理
  2. Linux SPI框架
  3. pat00-自测2. 素数对猜想 (20)
  4. MySQL Range Optimization
  5. Unity3D - UGUI组件的中英文对照
  6. linux内核mtd分区,嵌入式Linux MTD分区调整(MX28)
  7. python中punctuation_Python中的字符串
  8. NIO+SocketChannel+Buffer+Selector 多路复用
  9. vrep和matlab,使用Matlab与V-REP联合仿真 - Play V-REP with Matlab
  10. html中设置字体字号,html中设置字体大小的方法
  11. 期货突破(期货突破交易法)
  12. 华为 IP源防攻击和MAC认证
  13. HDU6069(数学)
  14. Layui设置table指定行的背景色
  15. Android照片墙加强版,使用ViewPager实现画廊效果
  16. HDFS集群内文件移动的Java实现
  17. 关于CNN中出现的诸如conv4_3、conv8_2、conv7等标识的含义
  18. UVa 12563 - Jin Ge Jin Qu hao(01背包)
  19. 根据一只猿前辈的TPLINK和海康威视漏扫工具改进的IPscanner成果展示(20170314 更新)...
  20. hp打印机装不上服务器系统安装,惠普1210打印机驱动为什么一直安装不上?

热门文章

  1. 阿里题目:明星群众问题
  2. hibernate+spring 注解 对事务的一些信息 (还没有整理)
  3. 关于Windows 2003 sp1不能打开CHM文件的问题
  4. ReactNative组件导出
  5. java supplier_现代化的 Java (二十一)——宏和生成宏
  6. CCF CSP201909-2 小明种苹果(续)
  7. 版权审查只会越来越严
  8. 小孩天天不愿意去幼儿园怎么办?
  9. 做生意失败是一种什么体验?创业中有哪些雷区需要注意?
  10. 了解一点儿JavaConfig