web开发中,文件的上传是非常基本功能之一。
在asp.net中,通常做法是利用webservice 来接收文件请求,这样做的好处就是全站有了一个统一的文件上传接口,并且根据网站的实际情况,可以将webservice部署到其他服务器上,可以兼容考虑将来的分布存储等等问题。
在MVC中实现文件上传主要有2中方式:
1.普通Controller实现文件上传
2.ApiController实现文件上传
普通Controller实现文件上传
在普通的Controller中实现文件上传时,需要使用到HttpPostedFileBase类 来接收文件。调用HttpPostedFileBase 实例对象的SaveAs()方法,就可以将文件保存在服务器中,示例代码如下:
HTML片段:
<h2>Upload</h2> @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <div> <h4>Select a file:</h4> <input name="files" id="files" type="file" /> <label id="lbError">@ViewBag.ErrorMessage</label> <input type="submit" name="submit" value="Upload" /> </div> }
Controller中的Action片段:
[HttpPost] public ActionResult Upload(IEnumerable<HttpPostedFileBase> files) { if (files == null || files.Count() == 0 || files.ToList()[0] == null) { ViewBag.ErrorMessage = "Please select a file!!"; return View(); } string filePath = string.Empty; Guid gid = Guid.NewGuid(); foreach (HttpPostedFileBase file in files) { filePath = Path.Combine(HttpContext.Server.MapPath("/Uploads/"), gid.ToString() + Path.GetExtension(file.FileName)); file.SaveAs(filePath); } return RedirectToAction("UploadResult", new { filePath = filePath }); } public ActionResult UploadResult(string filePath) { ViewBag.FilePath = filePath; return View(); }
需要注意2个问题:
1. 注意给form表单加上enctype = "multipart/form-data" 属性,否则会导致Action的参数HttpPostedFileBase 对象接收不到文件。
2. 注意文件大小,IIS中默认上传的文件大小为4MB ,超过这大小的文件需要在修改配置文件。
上传大文件时修改文件大小限制如下:
第一步:asp.net中的文件大小限制
<system.web> <httpRuntime maxRequestLength="153600" executionTimeout="900" /> </system.web>
第二步:IIS中文件大小限制
<system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="157286400" /> </requestFiltering> </security> </system.webServer>
ApiController实现文件上传
通过ApiController来实现文件上传时,不得不参考一下 官方文档了,建议先去阅读一下。
我自己在实现Demo时, 开发环境为.net 4.0。
HTML片段:
<h2>API Upload</h2> <form name="apiForm" method="post" enctype="multipart/form-data" action="/api/upload"> <div> <label for="apifiles">Select a File</label> <input name="apifiles" type="file" /> </div> <div> <input type="submit" value="Upload" /> </div> </form>
ApiController代码:
public class UploadController : ApiController { public Task<HttpResponseMessage> PostFormData() { if (!Request.Content.IsMimeMultipartContent()) { throw new Exception(""); } string root = HttpContext.Current.Server.MapPath("/Uploads/"); var provider = new ReNameMultipartFormDataStreamProvider(root); var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(t => { if (t.IsFaulted || t.IsCanceled) { Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception); } string fileName = string.Empty; foreach (MultipartFileData file in provider.FileData) { fileName = file.LocalFileName; } //返回上传后的文件全路径 return new HttpResponseMessage() { Content = new StringContent(fileName) }; }); return task; } } /// <summary> /// 重命名上传的文件 /// </summary> public class ReNameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider { public ReNameMultipartFormDataStreamProvider(string root) : base(root) { } public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers) { //截取文件扩展名 string exp = Path.GetExtension(headers.ContentDisposition.FileName.TrimStart('"').TrimEnd('"')); string name = base.GetLocalFileName(headers); return name + exp; } }
如上代码,区别与官网给出的.net 4.0 版本的代码的。
请注意: ReNameMultipartFormDataStreamProvider 为自定义类,继承自MultipartFormDataStreamProvider, 这个累的目的就是对上传上来的文件在保存到服务器时,保留文件的扩展名。MultipartFormDataStreamProvider类默认保存的文件是没有扩展名称的。当然我自己这里实现的方式的确挺土的,演示Demo明白思议即可,呵呵。
到这里就差不多了,后面准备实现Ajax+SingR来实现文件上传时显示上传进度的Demo。
参考资料:
Confusing required maxRequestLength and maxAllowedContentLength settings
关于MVC4.0 WebAPI上传图片重命名以及图文结合
ASP.NET Web Api Self Host大文件上传功能