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异步上传并客户端验证类型和大小 ...
随机推荐
- c++实现的Array数据结构
1.Array.h,Array<T>的定义 template <class T> class Array { protected: T *data; //一个指向数组数据的指针 ...
- SGU 148.B-Station
时间限制:0.25s 空间限制:4M 题目 在离著名的国家Berland不远的地方,有一个水下工作站.这个工作站有N层.已知:是第层装有Wi的水,最多可以容纳Li的水,恐怖分子炸毁第i的代价是Pi. ...
- ie11下,插入框架Html
if(navigator.userAgent.indexOf("MSIE")>0 || (navigator.userAgent.indexOf("Trident& ...
- WordPress批量修改文章内容、URL链接、文章摘要
通过SQL语句来批量修改wordpress博客内容,文章中所有语句都使用默认的wp_表前缀,如果您的数据表前缀不是wp_则需要在语句中作相应更改. 方法/步骤 批量修改文章内容 如果您想替换之前写 ...
- 【C语言】严格区分大小写
C语言严格区分大小写 一.相关基础知识 二.具体内容 C语言严格区分大小写: 如: int为关键字,INT则为用户标识符,即可定义int INT; int INt; int Int; cha ...
- crf 分词(待)
http://blog.csdn.net/marising/article/details/5769653
- 查看Ubuntu操作系统位数
查看系统是32位还是64位 #查看long的位数,返回32或64 getconf LONG_BIT
- Agri-Net poj 1258
WA了好多次,注意语言和数据范围 Description Farmer John has been elected mayor of his town! One of his campaign pro ...
- db2索引创建和删除
在表trpt_jv_rpt_log_td的tim列上创建索引 create index dw_rpt.irpt_jv_rpt_log_td_tim on dw_rpt.trpt_jv_rpt_log_ ...
- C#程序设计基础——类、对象、方法
类与对象 类 类是一种构造,通过使用该构造,用户可以将其他类型的变量.方法和事件组合在一起,从而创建自定义类型.类就像一个蓝图,它定义类型的数据和行为. 对象 定义类之后,便可通过将类加载到内存中来使 ...