一、WebApi上使用MultipartFormDataStreamProvider來接收文件時,會自動將文件保存至指定目錄下,文件名什么的都是自動生成的。代碼如下:
[HttpPost, Route("savefiles")] public async Task<bool> SaveFile(string projectId, string eventId) { if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string root = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["FileStorePath"]), DateTime.Now.ToShortDateString(), projectId); if (!Directory.Exists(root)) Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); try { await Request.Content.ReadAsMultipartAsync(provider); } catch (Exception ex) { WebConfig.LoggerInstance.Error("上傳文件出現異常:" + ex.Message); } return true;
然后在客戶端調用如下代碼即可
public async static Task<bool> UploadFile(string url, string fileName) { HttpClient httpClient = new HttpClient(); var multipartContent = new MultipartFormDataContent(); using (Stream stream = File.OpenRead(fileName)) { multipartContent.Add(new StreamContent(stream), "test", "test.txt"); var responseMessage = await httpClient.PostAsync(url, multipartContent); Task<string> body = responseMessage.Content.ReadAsStringAsync(); if ("OK".Equals(responseMessage.StatusCode.ToString())) return true; else return false; } }
二、自己保存文件
首先看下下面的uml 圖,圖中相關類為Microsoft默認提供的MIME處理類,最后的MultipartFormDataStreamProvider也在前篇博客中有介紹用法,如果要實現開發自定義如何保存文件,按個人最開始的想法是只要繼承MultipartFormDataStreamProvider,並重載相關方法即可
實現代碼如下
/// <summary> /// 與MultipartFormDataStreamProvider對應,但不將文件直接存入指定位置,而是需要自己指定數據流如何保存 /// </summary> public class MultipartFormDataMemoryStreamProvider : MultipartStreamProvider { private NameValueCollection _formData = new NameValueCollection(); private Collection<bool> _isFormData = new Collection<bool>(); /// <summary> /// 獲取文件對應的HttpContent集合,文件如何讀取由實際使用方確定,可以ReadAsByteArrayAsync,也可以ReadAsStreamAsync /// </summary> public Collection<HttpContent> FileContents { get { if (this._isFormData.Count != this.Contents.Count)//兩者總數不一致,認為未執行過必須的Request.Content.ReadAsMultipartAsync(provider)方法 { throw new InvalidOperationException("System.Net.Http.HttpContentMultipartExtensions.ReadAsMultipartAsync must be called first!"); } return new Collection<HttpContent>(this.Contents.Where((ct, idx) => !this._isFormData[idx]).ToList()); } } public NameValueCollection FormData { get { return this._formData; } } public override async Task ExecutePostProcessingAsync() { for (var i = 0; i < this.Contents.Count; i++) { if (!this._isFormData[i])//非文件 { continue; } var formContent = this.Contents[i]; ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition; string formFieldName = UnquoteToken(contentDisposition.Name) ?? string.Empty; string formFieldValue = await formContent.ReadAsStringAsync(); this.FormData.Add(formFieldName, formFieldValue); } } public override Stream GetStream(HttpContent parent, HttpContentHeaders headers) { if (parent == null) { throw new ArgumentNullException("parent"); } if (headers == null) { throw new ArgumentNullException("headers"); } ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition; if (contentDisposition == null) { throw new InvalidOperationException("Content-Disposition is null"); } this._isFormData.Add(string.IsNullOrEmpty(contentDisposition.FileName)); return new MemoryStream(); } /// <summary> /// 復制自 System.Net.Http.FormattingUtilities 下同名方法,因為該類為internal,不能在其它命名空間下被調用 /// </summary> /// <param name="token"></param> /// <returns></returns> private static string UnquoteToken(string token) { if (string.IsNullOrWhiteSpace(token)) { return token; } if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1) { return token.Substring(1, token.Length - 2); } return token; } }
然后在在webapi端,使用
var provider = new MultipartFormDataMemoryStreamProvider();
就可以了
var provider = new MultipartFormDataMemoryStreamProvider(); try { await Request.Content.ReadAsMultipartAsync(provider); foreach (var item in provider.Contents) { var ms = item.ReadAsStreamAsync().Result; using (var br = new BinaryReader(ms)) { var data = br.ReadBytes((int)ms.Length); File.WriteAllBytes(root + "/"+eventId+".txt", data); } } } catch (Exception ex) { WebConfig.LoggerInstance.Error("上傳文件出現異常:" + ex.Message); }