# History [[WebApi] 捣鼓一个资源管理器--文件下载](http://blog.csdn.net/qiujuer/article/details/41621781) # In This 既然访问文件接口有了,怎么能少的了文件的上传接口呢! 既然是文件上传接口那就肯定要来一个猛一点的接口--多文件上传 ![](https://box.kancloud.cn/2016-01-11_5693565ab7a47.jpg) # CodeTime ##### 改动 进入正题前先来看看本次改动的文件有哪些: ![](https://box.kancloud.cn/2016-01-11_5693565ac61bc.jpg) 可以看见一共有4个文件进行了改动,其中Home与ResourceApi是添加了方法,Model/Resource是新增,View/Upload也是新增。 ##### Model部分 为了返回数据简单方便,所以**New** 了一个类 **Resource.cs** ~~~ namespace WebResource.Models { public class Resource { public string Id { get; set; } public string Type { get; set; } } } ~~~ **If Easy?** ##### ResourceApi 部分 然后来看看咱们的**ResourceApi**类: ~~~ namespace WebResource.Controllers { [RoutePrefix("Resource")] public class ResourceApiController : ApiController { private static readonly long MEMORY_SIZE = 64 * 1024 * 1024; private static readonly string ROOT_PATH = HttpContext.Current.Server.MapPath("~/App_Data/"); [HttpGet] [Route("{Id}")] public async Task<HttpResponseMessage> Get(string Id) { // 进入时判断当前请求中是否含有 ETag 标识,如果有就返回使用浏览器缓存 // Return 304 var tag = Request.Headers.IfNoneMatch.FirstOrDefault(); if (Request.Headers.IfModifiedSince.HasValue && tag != null && tag.Tag.Length > 0) return new HttpResponseMessage(HttpStatusCode.NotModified); // 进行模拟 App_Data/Image/{id}.png // 打开找到文件 FileInfo info = new FileInfo(Path.Combine(ROOT_PATH, "Image", Id + ".png")); if (!info.Exists) return new HttpResponseMessage(HttpStatusCode.BadRequest); FileStream file = null; try { // 打开文件 file = new FileStream(info.FullName, FileMode.Open, FileAccess.Read, FileShare.Read); HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); // 在浏览器中显示 inline ContentDispositionHeaderValue disposition = new ContentDispositionHeaderValue("inline"); // 写入文件基本信息 disposition.FileName = file.Name; disposition.Name = file.Name; disposition.Size = file.Length; // 判断是否大于64Md,如果大于就采用分段流返回,否则直接返回 if (file.Length < MEMORY_SIZE) { //Copy To Memory And Close. byte[] bytes = new byte[file.Length]; await file.ReadAsync(bytes, 0, (int)file.Length); file.Close(); MemoryStream ms = new MemoryStream(bytes); result.Content = new ByteArrayContent(ms.ToArray()); } else { result.Content = new StreamContent(file); } // 写入文件类型,这里是图片png result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); result.Content.Headers.ContentDisposition = disposition; // 设置缓存信息,该部分可以没有,该部分主要是用于与开始部分结合以便浏览器使用304缓存 // Set Cache result.Content.Headers.Expires = new DateTimeOffset(DateTime.Now).AddHours(1); // 这里应该写入文件的存储日期 result.Content.Headers.LastModified = new DateTimeOffset(DateTime.Now); result.Headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromHours(1) }; // 设置Etag,这里就简单采用 Id result.Headers.ETag = new EntityTagHeaderValue(string.Format("\"{0}\"", Id)); // 返回请求 return result; } catch { if (file != null) { file.Close(); } } return new HttpResponseMessage(HttpStatusCode.BadRequest); } [HttpPost] [Route("Upload")] [ResponseType(typeof(Resource))] public async Task<IHttpActionResult> Post() { List<Resource> resources = new List<Resource>(); // multipart/form-data // 采用MultipartMemoryStreamProvider var provider = new MultipartMemoryStreamProvider(); //读取文件数据 await Request.Content.ReadAsMultipartAsync(provider); foreach (var item in provider.Contents) { // 判断是否是文件 if (item.Headers.ContentDisposition.FileName != null) { //获取到流 var ms = item.ReadAsStreamAsync().Result; //进行流操作 using (var br = new BinaryReader(ms)) { if (ms.Length <= 0) break; //读取文件内容到内存中 var data = br.ReadBytes((int)ms.Length); //Create //当前时间作为ID Resource resource = new Resource() { Id = DateTime.Now.ToString("yyyyMMddHHmmssffff", DateTimeFormatInfo.InvariantInfo) }; //Info FileInfo info = new FileInfo(item.Headers.ContentDisposition.FileName.Replace("\"", "")); //文件类型 resource.Type = info.Extension.Substring(1).ToLower(); //Write try { //文件存储地址 string dirPath = Path.Combine(ROOT_PATH); if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } File.WriteAllBytes(Path.Combine(dirPath, resource.Id), data); resources.Add(resource); } catch { } } } } //返回 if (resources.Count == 0) return BadRequest(); else if (resources.Count == 1) return Ok(resources.FirstOrDefault()); else return Ok(resources); } } } ~~~ 与上一章比较看来,只是增加了一个方法 Post ,而后将其重定向为**Resource/Upload ** 其中主要干了些什么我都在方法中注明了;应该是足够简单的。 现在运行一下,看看我们的**Api**是怎样的: ![](https://box.kancloud.cn/2016-01-11_5693565ad7d31.jpg) 下面我们来调用它试试。 ##### HomeController部分 修改HomeController 添加一个Upload 方法: ~~~ namespace WebResource.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Title = "Home Page"; return View(); } public ActionResult Upload() { return View(); } } } ~~~ ##### Upload.cshtml部分 而后在方法上点击右键添加视图,然后进入**View/Home/Upload.cshtml** 视图中修改为: ~~~ @{ ViewBag.Title = "Upload"; } <h2>Upload</h2> <div id="body"> <h1>多文件上传模式</h1> <section class="main-content clear-fix"> <form name="form1" method="post" enctype="multipart/form-data" action="/Resource/Upload"> <fieldset> <legend>File Upload Example</legend> <div> <label for="caption">File1</label> <input name="file1" type="file" /> </div> <div> <label for="image1">File2</label> <input name="file2" type="file" /> </div> <div> <input type="submit" value="Submit" /> </div> </fieldset> </form> </section> </div> ~~~ 在该视图中,我们建立了一个 **Form** 表单,然后指定为 **Post** 模式;同时指定 **enctype="multipart/form-data" action="/Resource/Upload"** # RunTime 写完了代码当然是调试运行喽! 运行 **localhost:60586/Home/Upload** 这里我们添加文件,还是使用上一章中的两种图片吧: ![](https://box.kancloud.cn/2016-01-11_5693565aec255.jpg) 运行后: ![](https://box.kancloud.cn/2016-01-11_5693565b542c7.jpg) 当然,这里是因为我的浏览器是谷歌浏览器,所以返回的是 **XML **数据,如果你的事IE浏览器那么应该返回的是**Json** 文件。 **WebApi**会根据请求返回不同的数据。 ![](https://box.kancloud.cn/2016-01-11_5693565b670c5.jpg) 可以看到,现在 **App_Data**文件夹下,多了两个文件了;不过这两个文件是没有加上文件类型的;你可以手动给他加上个**.png** 然后打开看看是不是那两张图片。 # END OK,这一章就到此为止了! ##### 资源文件 [第一章资源文件(说好了这章中添加)](http://download.csdn.net/detail/qiujuer/8215741) [第二章资源文件](http://download.csdn.net/detail/qiujuer/8215787) ##### 下一章 下一章将会把上传与下载查看两个方法相互结合,搭配起来;同时将会结合数据进行辅助存储文件信息。 同时,会讲如何避免文件重复上传的问题。 已更新:[[WebApi] 捣鼓一个资源管理器--多文件上传+数据库辅助](http://blog.csdn.net/qiujuer/article/details/41721165)