MVC 文件上传
项目需要,做一个图片上传的功能,本来是很简单,但是需要同时上传多个文件,并分条带一些额外的信息,听上去很复杂,通过下面图就可以一目了然:

网上找过一些方法,但多为不支持图片与其他信息关联,或者分两次上传(文件一次,返回一个indicator,然后通过json传其他信息),不理想。偶然发现一个MVC的方法,思路非常简单,就是MVC,独特之处是把图片作为一个HttpPostedFileBase类型的属性存到ViewModel里。直接看代码:
<form action="" method="post" enctype="multipart/form-data">
@for (int i = ; i < Model.Count; i++)
{
<div class="col-xs-11 row space-top">
<div class="col-xs-2">
@Html.EditorFor(m => m[i].Title)
</div>
<div class="col-xs-2">
@Html.EditorFor(m => m[i].AltText)
</div>
<div class="col-xs-2">
@Html.EditorFor(m => m[i].Caption)
</div>
<div class="col-xs-3">
@Html.TextBoxFor(m => m[i].ImageUpload, new { type = "file" })
</div>
</div>
}
<div class="container space-top" >
<button class="btn col-xs-2 space-top" type="submit">Create</button>
</div>
</form>
View
// GET: Image
public ActionResult Create()
{
var models = new List<ImageViewModel>();
models.Add(new ImageViewModel());
models.Add(new ImageViewModel());
return View(models);
}
Controller
public class ImageViewModel
{
[Required]
public string Title { get; set; } public string AltText { get; set; } [DataType(DataType.Html)]
public string Caption { get; set; } [DataType(DataType.Upload)]
public HttpPostedFileBase ImageUpload { get; set; }
}
ViewModel
[HttpPost]
public ActionResult Create(List<ImageViewModel> models)
{
var model = models[];
var validImageTypes = new string[] { "image/gif", "image/jpeg", "image/pjpeg", "image/png" }; if (model.ImageUpload == null || model.ImageUpload.ContentLength == )
{
ModelState.AddModelError("ImageUpload", "This field is required");
}
else if (!validImageTypes.Contains(model.ImageUpload.ContentType))
{
ModelState.AddModelError("ImageUpload", "Please choose either a GIF, JPG or PNG image.");
}
if (ModelState.IsValid)
{
var image = new Image
{
Title = model.Title,
AltText = model.AltText,
Caption = model.Caption
}; if (model.ImageUpload != null && model.ImageUpload.ContentLength > )
{
//var uploadDir = "~/uploads";
//var imagePath = Path.Combine(Server.MapPath(uploadDir), model.ImageUpload.FileName);
//var imageUrl = Path.Combine(uploadDir, model.ImageUpload.FileName);
//model.ImageUpload.SaveAs(imagePath);
//image.ImageUrl = imageUrl;
}
//db.Create(image);
//db.SaveChanges();
// return RedirectToAction("Index");
} return View(models);
}
Post Action
发现原来还可以这样,但是由于我使用的knockout,所以提交数据需要用JS完成,需要将其转换,但当我构建完对象,将其转换为JSON的时候,发现文件不是随便就能序列化的。观察上面例子提交的请求:


跟普通的Form相比,并无特殊之处,说明只要content-type为mutipart/form-data,Form的name按照序号加名称的格式填写,Action就能获得到指定的数据,我将代码改为这种形式:
<form action="Create" encType="multipart/form-data" method="post">
<div>
<label for="">Title</label>
<input name="[0].Title" type="text" value="a">
</div>
<div>
<label for="">AltText</label>
<input name="[0].AltText" type="text" value="a">
</div>
<div>
<label for="">Caption</label>
<input name="[0].Caption" type="text" value="a">
</div>
<div>
<label for="">ImageUpload</label>
<input name="[0].ImageUpload" type="file">
</div>
<div>
<label for="">Title</label>
<input name="[1].Title" type="text" value="b">
</div>
<div>
<label for="">AltText</label>
<input ame="[1].AltText" type="text" value="b">
</div>
<div>
<label for="">Caption</label>
<input name="[1].Caption" type="text" value="b">
</div>
<div>
<label for="">ImageUpload</label>
<input name="[1].ImageUpload" type="file">
</div>
<button type="submit">Create</button>
</form>
HTML
依然work,说明推论合理。然后做进一步修改:
function mySubmit() {
var formData = new FormData();
formData.append("[0].Title", $("[name='[0].Title'").val());
formData.append("[0].AltText", $("[name='[0].AltText'").val());
formData.append("[0].Caption", $("[name='[0].Caption'").val());
formData.append("[0].ImageUpload", $("[name='[0].ImageUpload'").get().files[]);
formData.append("[1].Title", $("[name='[1].Title'").val());
formData.append("[1].AltText", $("[name='[1].AltText'").val());
formData.append("[1].Caption", $("[name='[1].Caption'").val());
formData.append("[1].ImageUpload", $("[name='[1].ImageUpload'").get().files[]);
console.log(formData);
$.ajax({
contentType: false,
url: "/Image/Create",
type: "POST",
processData: false,
dataType: 'json',
data: formData,
success: function (result) {
},
error: function (err) {
alert(err.statusText);
}
});
}
JS
注意把contentType和processData都设为false,防止AJAX自己修改数据格式。
到这里本来问题就解决了,但是,但是,IE9及以下不支持FormData,于是做了进一步修改,以来表单的提交功能,JS里构建需要的<input type="hidden" />,设置好name属性,然后提交表单$("#Form").submit(),思路就是这样,代码就不写了。
其实,这里的原理我还是不大清楚,为什么action能将这样的一个name list还原为对象,我猜跟negotiation有关系,还需要进一步研究。
MVC 文件上传的更多相关文章
- MVC文件上传-使用jQuery.FileUpload和Backload组件实现文件上传
本篇使用客户端jQuery-File-Upload插件和服务端Badkload组件实现多文件异步上传.MVC文件上传相关兄弟篇: 处理文件上传的服务端组件Backload 用于处理文件上传的服务端组件 ...
- ASP.NET MVC 文件上传和路径处理
ASP.NET MVC 文件上传和路径处理总结 目录 文件的上传和路径处理必须解决下面列出的实际问题: 1.重复文件处理 2.单独文件上传 3.编辑器中文件上传 4.处理文章中的图片路径 5.处理上传 ...
- MVC文件上传与下载
MVC文件上传与下载 MVC文件上传与下载 想想自己从毕业到工作也有一年多,以前公司的任务的比较重,项目中有的时候需要用到什么东西都去搜索一下,基础知识感觉还没有以前在学校中的好.最近开始写博客,真的 ...
- Spring MVC 笔记 —— Spring MVC 文件上传
文件上传 配置MultipartResolver <bean id="multipartResolver" class="org.springframework.w ...
- MVC文件上传09-使用客户端jQuery-File-Upload插件和服务端Backload组件让每个用户有专属文件夹,并在其中创建分类子文件夹
为用户创建专属上传文件夹后,如果想在其中再创建分类子文件夹,该怎么做?可以在提交文件的视图中再添加一个隐藏域,并设置 name="uploadContext". 相关兄弟篇: MV ...
- MVC文件上传08-使用客户端jQuery-File-Upload插件和服务端Backload组件让每个用户有专属文件夹
当需要为每个用户建立一个专属上传文件夹的时候,可以在提交文件的视图中添加一个隐藏域,并设置name="objectContext". 相关兄弟篇: MVC文件上传01-使用jque ...
- MVC文件上传07-使用客户端jQuery-File-Upload插件和服务端Backload组件裁剪上传图片
本篇通过在配置文件中设置,对上传图片修剪后保存到指定文件夹. 相关兄弟篇: MVC文件上传01-使用jquery异步上传并客户端验证类型和大小 MVC文件上传02-使用HttpPostedFileB ...
- MVC文件上传06-使用客户端jQuery-File-Upload插件和服务端Backload组件自定义控制器上传多个文件
当需要在控制器中处理除了文件的其他表单字段,执行控制器独有的业务逻辑......等等,这时候我们可以自定义控制器. MVC文件上传相关兄弟篇: MVC文件上传01-使用jquery异步上传并客户端验证 ...
- MVC文件上传05-使用客户端jQuery-File-Upload插件和服务端Backload组件自定义上传文件夹
在零配置情况下,文件的上传文件夹是根目录下的Files文件夹,如何自定义文件的上传文件夹呢? MVC文件上传相关兄弟篇: MVC文件上传01-使用jquery异步上传并客户端验证类型和大小 MVC文 ...
- MVC文件上传04-使用客户端jQuery-File-Upload插件和服务端Backload组件实现多文件异步上传
本篇使用客户端jQuery-File-Upload插件和服务端Badkload组件实现多文件异步上传.MVC文件上传相关兄弟篇: MVC文件上传01-使用jquery异步上传并客户端验证类型和大小 ...
随机推荐
- $.cookie('name', null) 删除cookie 失效问题
这几天在做网站的用户登录和退出功能,我使用jquery.cookie.js来操作cookie,但是用$.cookie('name', null) 总是失效, 后来使用$.cookie("na ...
- javascript基础学习(五)
javascript之函数 学习要点: 函数的介绍 函数的参数 函数的属性和方法 系统函数 一.函数的介绍 1.函数就是一段javascript代码.可以分为用户自定义函数和系统函数. 如果一个函 ...
- extern "C" {} 来沟通C和C++
比如说你用C++开发了一个DLL库,为了能够让C语言也能够调用你的DLL输出(Export)的函数,你需要用extern "C"来强制编译器不要修改你的函数名. 通常,在C语言的头 ...
- Bootstrap_Javascript_提示框
一. 结构分析 在Bootstrap框架中的提示框,结构非常简单,常常使用的是按钮<button>标签或者链接<a>标签来制作.不管是使用按钮还是链接来制作提示框,他们都有一个 ...
- Canvas中点到点的路径运动
/*随机生成两个点,然后以两点为端点,进行运动,主要使用了SetInterval,对画布进行不断的擦除描绘的操作*/1 <!DOCTYPE html> <html xmlns=&qu ...
- 入门5:PHP 语法基础——流程控制
一.if...else 语句 if( ) else{ } 如果 .... 就.... 否则.... if(判断){ 判断成立 则执行该表达式 }else{ 如果上方判断都不成立 则执行该表达式 } i ...
- wdcp对default站点开启apache url重写功能
网站开启对default网站的重写功能
- magento后台 Fatal error: Call to a member function getId() on a non-object in错误
后台分类管理出现错误 Fatal error: Call to a member function getId() on a non-object in 在数据库中运行以下sql语句 INSERT I ...
- JQuery解析HTML、JSON和XML实例详解
1.HTML 有的时候会将一段HTML片段保存在HTML文件中,在另外的主页面直接读取该HTML文件,然后解析里面的HTML代码片段融入到主页面中. fragment.html文件,其内容: 复制代码 ...
- Android各种访问权限Permission详解
原文:http://jingyan.baidu.com/article/afd8f4de4688af34e386e976.html 在Android的设计中,资源的访问或者网络连接,要得到这些服务都需 ...