2014-12-22 34 views
1

我試圖上傳一個文件異步到我的web服務器(ASP.NET MVC)。具體到我的web api端點。我跟着幾個教程,但我不斷收到空參數的錯誤。錯誤與ReadAsMultipartAsync和MultiPartFormDataStreamProvider

它發生在我的子類MultipartFormDataStreamProvider。方法GetLocalFileName,被正確調用第一個正確的HttpContentHeaders,但隨後被null標頭第二次調用。

該文件成功地保存了我設置的文件名,但是當我收到一個異常時,我無法知道生成的名稱是什麼。

但是,如果我只使用基類MultipartFormDataStreamProvider類,該文件完美保存,沒有錯誤,但在這種情況下我無法控制文件名。

這是API方法:

[HttpPost] 
    public async Task<FilesUploadResult> Save() 
    { 
     // Check if the request contains multipart/form-data. 
     if (!Request.Content.IsMimeMultipartContent()) 
     { 
      var ret = new FilesUploadResult(HttpStatusCode.UnsupportedMediaType, null); 
      ret.Message = "Unsupported Media Type. Request must contain multipart/form-data form."; 
      return ret; 
     } 

     var path = UploadsFolderPath; 

     // to-do: this works but for some reason makes a call with empty headers. 
     var provider = new SimpleMultipartFormDataStreamProvider(path); 

     // this provider saves the file with an arbritrary name 
     //var provider = new MultipartFormDataStreamProvider(path); 

     try 
     { 
      // Read the form data. 
      await Request.Content.ReadAsMultipartAsync(provider as MultipartFormDataStreamProvider); 

      var files = from f in provider.FileData 
         let info = new FileInfo(f.LocalFileName) 
         select new FileUploadDescription(info.Name, path + "\\" + info.Name, info.Length, HttpStatusCode.Created); 

      var ret = new FilesUploadResult(HttpStatusCode.OK, files); 
      return ret; 
     } 
     catch (Exception ex) 
     { 
      var ret = new FilesUploadResult(HttpStatusCode.InternalServerError, null); 
      ret.Message = ex.Message; 
      return ret; 
     } 
    } 

這是我SimpleMultipartFormDataStreamProvider代碼:

public class SimpleMultipartFormDataStreamProvider : MultipartFormDataStreamProvider 
{ 
    public SimpleMultipartFormDataStreamProvider(string path) : base(path) { } 

    public override string GetLocalFileName(HttpContentHeaders headers) 
    { 

     // make sure the headers are valid 
     if (headers == null) 
     { 

      throw new ArgumentNullException("headers"); 
     } 

     // filename 
     var filename = CleanString(headers.ContentDisposition.FileName); ; 

     // create the local file name 
     var localFileName = string.Format("_{0}_{1}", GetRandomName(), filename); 

     //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped 
     return localFileName.Replace("\"", string.Empty); 
    } 

    private string GetRandomName() 
    { 
     return GuidHelper.ShortUniqueId(16); 
    } 

    private static string CleanString(string str) 
    { 
     if (string.IsNullOrWhiteSpace(str)) 
      return string.Empty; 

     var sb = new StringBuilder(); 
     foreach (char c in str) 
     { 
      if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_') 
      { 
       sb.Append(c); 
      } 
     } 
     return sb.ToString(); 
    } 
} 

誰能告訴我爲什麼我收到了GetLocalFileName叫兩次,第二次空頭?

回答

2

我自己想通了。

問題是我實施的子類MultipartDataStreamProvider的類是在不同的項目中。

該項目引用了與當前Web Api項目中不同的.Net .Http程序集。

我做的唯一的事情就是將CustomMultipartDataStreamProvider類移動到同一個項目中,並且一切都很完美。

+0

這是我的問題。讓我把頭髮拉出一個下午。非常感謝! – CountZero

2

即使我在MVC4中遇到了這樣的行爲,它提交了2個文件之一是空的,所以更好的辦法是檢查文件是否有任何內容,然後繼續保存文件。 可以有這多種方法: 其中之一將是從Request.Files得到所有的文件列表(這是一個字符串數組)

 foreach (string fileName in Request.Files) 
      { 
       HttpPostedFileBase file = Request.Files[fileName]; 
       //Save file content goes here 
       if (file != null && file.ContentLength > 0) 
       { 
        //logic to save the content 
       } 
      } 
+0

謝謝你的回答@ nikitech-kolpe,但我不確定你指的是什麼Request對象。在我的WebApi控制器內部,我的Request對象沒有任何名爲Files的屬性。還有什麼我可能會失蹤? – jsicary

2

GetLocalFileName是在多每個文件調用一次請求。如果您在同一請求中發送兩個文件GetLocalFileName將被調用兩次。我想你應該檢查你是如何調用服務,並使用fiddler或類似的東西,看看你是否真的發送兩個文件。如果您在同一個請求中發送多個部分,請嘗試指定每個部分的ContentType。

+0

我會注意到這一點,但我不認爲這是問題,因爲當我使用默認的MultipartFormDataStreamProvider時,我不會收到任何錯誤,它只會保存一個文件。 – jsicary