WebAPI开发中,经常会使用multipart/form-data方式来实现文件的上传。而网上流传甚广的就是下面这样一份代码。但是,这份代码有个问题,就是初始化MultipartFormDataStreamProvider类或者子类时,需要制定文件的保存路径。但是,有些应用场景是无法指定这个路径的,比如由于安全问题不允许直接进行文件的写入。有时候,甚至没必要指定这个路径,因为只需要读取传递过来的文件对应的byte数组即可。那么本文针对这种情况给出了一种解决方法。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
namespace UploadApplication.Controllers
{
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string fileSaveLocation = HttpContext.Current.Server.MapPath("~/App_Data");
CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(fileSaveLocation);
List<string> files = new List<string>();
Dictionary<string, string> dic = new Dictionary<string, string>();
try
{
await Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{//接收FileData
files.Add(Path.GetFileName(file.LocalFileName));
}
foreach (var key in provider.FormData.AllKeys)
{//接收FormData
dic.Add(key, provider.FormData[key]);
}
return Request.CreateResponse(HttpStatusCode.OK, files);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public CustomMultipartFormDataStreamProvider(string path) : base(path) { }
public override string GetLocalFileName(HttpContentHeaders headers)
{
return headers.ContentDisposition.FileName.Replace("\"", string.Empty);
}
}
}
下面的代码直接从请求的Content中读取请求数据,得到MultipartMemoryStreamProvider对象,遍历该对象的Contents属性,可以得到包含上传文件及form表单数据的HttpContent对象。如何从Contents找到包含文件数据的HttpContent对象,可以根据HttpContent对象头部中对应的FileName属性来判断,这个需要和前端约定好,文件数据必须传入文件名称。
var multipartMemoryStreamProvider = await Request.Content.ReadAsMultipartAsync();
Dictionary<string, string> dic = new Dictionary<string, string>();
foreach (var content in multipartMemoryStreamProvider.Contents)
{
if (!string.IsNullOrEmpty(content.Headers.ContentDisposition.FileName))
{
using (Stream stream = await content.ReadAsStreamAsync())
{
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
}
}
else
{
string val = await content.ReadAsStringAsync();
dic.Add(content.Headers.ContentDisposition.Name, val);
}
}