ASP.NET Web Api Self Host大文件上傳功能


  今天同事在使用ASP.NET WebApi開發一個文件上傳功能時發現WebApi無法實現大文件上傳功能,於是向我求助。

 

  當我知道這個問題的時候第一反應是WebApi不可能不支持,於是就開始查看他的代碼:

 

View Code
 1 var config = new HttpSelfHostConfiguration("http://localhost:8080");
 2 
 3                 config.Routes.MapHttpRoute(
 4                     name: "DefaultApi",
 5                     routeTemplate: "api/{controller}/{action}"
 6                 );
 7 
 8                 HttpSelfHostServer server = new HttpSelfHostServer(config);
 9 
10                 server.OpenAsync().Wait();
11 
12                 Console.WriteLine("Server Started..");

 發現如下問題:

1.MaxReceivedMessageSize沒有更改為更大的值,默認為65536,當接收消息超過這個數值時服務器將會終止接收。

2.發現並未更改傳輸模式,即TransferMode,TransferMode有兩種模式,一種為Buffer模式,Buffer模式會將文件接收到緩沖區中,直到文件完整接收完成才會交由程序處理,

  當上傳的文件大小比Buffer還要大的時候,由於文件尚未接收完成緩沖區已經滿了,因此會發生異常。TransferMode的Stream模式解決了這個問題,Stream與Buffer模式不同,Stream模式能夠支持文件

  一邊接收一邊保存,這樣就可以解決大文件傳輸的問題了。

 

  但是有人會問那Buffer模式有什么用?其實Buffer模式也有它的應用場景,一般用於可靠傳輸,即要不全部接收,要不都不接收。猜測WS里的可靠傳輸就是這么實現的。

 

修改后代碼:

View Code
 1 var config = new HttpSelfHostConfiguration("http://localhost:8080");
 2 
 3                 //設置最大接收消息大小
 4                 config.MaxReceivedMessageSize = int.MaxValue;
 5                 //將默認緩沖形式的數據傳輸模式改為流模式, 緩沖模式需要將所有數據接收完成后才會寫入, 流模式可以一邊接收一邊寫入一般用於大數據量文件傳輸
 6                 config.TransferMode = TransferMode.Buffered;
 7 
 8                 config.Routes.MapHttpRoute(
 9                     name: "DefaultApi",
10                     routeTemplate: "api/{controller}/{action}"
11                 );
12 
13                 HttpSelfHostServer server = new HttpSelfHostServer(config);
14 
15                 server.OpenAsync().Wait();
16 
17                 Console.WriteLine("Server Started..");

代碼修改后大文件接收成功,但是發現接收后的文件無法打開或者格式錯誤等問題,查看同事開發的客戶端,是使用WebClient.UploadFile方法上傳文件的,Upload方法使用Post方式上傳,因此使用Fiddler模擬文件上傳請求,發現使用Post方法上傳文件時Http Request Body中存在一些分隔符類的字符

Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler

---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="IMG_2116.JPG"
Content-Type: image/jpeg

<@INCLUDE *C:\Users\kuangfenlin\Desktop\IMG_2116.JPG*@>
---------------------------acebdf13572468--

 

通過Google發現這其實是一個同時上傳多個文件的標准,多個文件或內容通過 boundary=-------------------------acebdf13572468 進行分割。

 

這樣就解釋了為什么文件接收后無法打開的問題,查看WebApi源代碼發現已經存在 MultipartFormDataStreamProvider 類型專門用於處理這種情況,修改Action代碼:

View Code
 1 if (!Request.Content.IsMimeMultipartContent())
 2             {
 3                 throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
 4             }
 5 
 6             string root = @"C:/";
 7             var provider = new MultipartFormDataStreamProvider(root);
 8 
 9             try
10             {
11                 StringBuilder sb = new StringBuilder();
12 
13                 var task = Request.Content.ReadAsMultipartAsync(provider);
14 
15                 task.Wait();
16 
17                 foreach (var file in provider.FileData)
18                 {
19                     FileInfo fileInfo = new FileInfo(file.LocalFileName);
20                     sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
21                 }
22                 return new HttpResponseMessage()
23                 {
24                     Content = new StringContent(sb.ToString())
25                 };
26             }
27             catch (System.Exception e)
28             {
29                 return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
30             }

嘿嘿,已經完美解決該問題啦!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM