# History
[[WebApi] 搗鼓一個資源管理器--文件下載](http://blog.csdn.net/qiujuer/article/details/41621781)
# In This
既然訪問文件接口有了,怎么能少的了文件的上傳接口呢!
既然是文件上傳接口那就肯定要來一個猛一點的接口--多文件上傳

# CodeTime
##### 改動
進入正題前先來看看本次改動的文件有哪些:

可以看見一共有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**是怎樣的:

下面我們來調用它試試。
##### 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**
這里我們添加文件,還是使用上一章中的兩種圖片吧:

運行后:

當然,這里是因為我的瀏覽器是谷歌瀏覽器,所以返回的是?**XML?**數據,如果你的事IE瀏覽器那么應該返回的是**Json**?文件。
**WebApi**會根據請求返回不同的數據。

可以看到,現在?**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)