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异步上传并客户端验证类型和大小 ...
随机推荐
- kafka监控
做kafka相关项目,需要用到监控的东东,找到了两个方法 第一个: http://quantifind.com/KafkaOffsetMonitor/ 非常容易上手,效果也直观,可以显示各个topic ...
- linxu 挂载分区
1. 添加新硬盘 设置 -> Storage -> SATA控制器->右击,选择“添加虚拟硬盘” 然后,根据需求创建合适的硬盘 2. 重启虚拟机 查看现有系统的磁盘空间 sudo f ...
- Spring MVC 获取前端参数的注解
在与前端交互的开发过程中,出现过几次无法取到参数的情况,费了些时间去排查问题,下面就简单总结一下. 注解详解 我们所要获取的前端传递参数大概可以分为以下四类: requet uri 部分的注解:@Pa ...
- 参数计数不匹配,未处理System.Reflection.TargetParameterCountException
系统出现异常:参数计数不匹配,未处理System.Reflection.TargetParameterCountException, 系统会显示如下的异常信息,但异常信息往往与实际异常位置差十万八千量 ...
- C#,新建的系统服务项目有些机器不能运行
检查了一下,是权限的问题 右键ProjectInstaller.cs 在设计界面里找到serviceProcessInstaller1右键属性 找到Account属性改为:LocalSystem
- dede定义全局变量(include/common.inc.php)及调用方式
dede定义全局变量的文件include/common.inc.php及使用 在include/common.inc.php文件里,dede定义了大量的全局变量,详细自己去看看 dede模板里 ...
- PHP 字符串常用方法
implode(“”,“”)-->字符串分割方法,第一个参数以什么样的形式分割,第二个参数需要分割的字符串 数组操作 is_array(),判断这个数是否是一个数组
- 一次性安装src.rpm编译所依赖的软件包
yum-builddep SRPMS/fcitx-4.2.8.4-4.1.cgdl21.src.rpm NAME yum-builddep - install missing depend ...
- 一个用得比较广的微信API的XXE外部实体注入漏洞
文件地址: https://github.com/dodgepudding/wechat-php-sdk/raw/master/wechat.class.php 代码: <?php /** * ...
- Unity3D批处理脚本
Unity3D批处理脚本 本文属于转载,如有侵权,请留言,我会及时删除! Max09在模型到处的模型和U3D场景的尺寸不一致,Max09中的1m导到U3D中,只有0.01m,这时可以在U3D中将模型的 ...