[WebApi] 捣鼓一个资源管理器–多文件上传
最后更新于:2022-04-01 06:57:07
# History
[[WebApi] 捣鼓一个资源管理器--文件下载](http://blog.csdn.net/qiujuer/article/details/41621781)
# In This
既然访问文件接口有了,怎么能少的了文件的上传接口呢!
既然是文件上传接口那就肯定要来一个猛一点的接口--多文件上传
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565ab7a47.jpg)
# CodeTime
##### 改动
进入正题前先来看看本次改动的文件有哪些:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/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://docs.gechiui.com/gc-content/uploads/sites/kancloud/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://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565aec255.jpg)
运行后:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565b542c7.jpg)
当然,这里是因为我的浏览器是谷歌浏览器,所以返回的是 **XML **数据,如果你的事IE浏览器那么应该返回的是**Json** 文件。
**WebApi**会根据请求返回不同的数据。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/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)