[ASP.NET] 如何把檔案上傳到WEB API?

研究背景:

最近協助朋友研究在公司網站建立新功能,讓客戶可以直接上傳檔案到公司的內部伺服器。

系統架構如下圖,檔案最後會放在公司內部的Web API Servr。而Web API接收上傳檔案的API是使用HTML的FormData格式


問題:
  • 網路上大部分教學是利用jquery ajax把檔案直接上傳到Web API上,可是公司Web API是內部使用的伺服器,所以只能透過Web Server存取。
解決方案:
以下是其中一種試過可行的做法。

  1. Web Server部分
    • Web API接收上傳檔案的API是使用HTML的FormData格式,所以當Web Server接收到Browser的上傳後需要把檔案轉成multipart/form-data的http Request,然後發送到後端的Web API去。產生的方法至少有兩種
    • 我們所使用的是REST Sharp。先讀取來自Browser的Request,然後把檔案變成multipart/form-data,再產生Http Request上傳到Web API。

      namespace /*project name*/.Controllers
      {
          public class FilesController : Controller
          {
              // GET: Files
              public string Upload()
              {
                  List<string> filesList = new List<string>();
                  try
                  {
                      foreach(string file in Request.Files)
                      {
                          var fileContent = Request.Files[file];
                          if (fileContent != null & fileContent.ContentLength > 0)
                          {
                              // get a stream
                              var stream = fileContent.InputStream;
      
                              RestRequest request = new RestRequest("resource/{id}", Method.POST);
                              request.AddFile("fileData", ReadToEnd(stream), null);
                              request.AddHeader("Content-Type", "multipart/form-data");
                              request.AlwaysMultipartFormData = true;                        
                              /*密碼跟username刪除掉*/
                              /**/
                              /**/
                              RestClient client = new RestClient(/*Web API的位置*/);
                              IRestResponse restResponse = client.Execute(request);
                              /*自己定義的回傳訊息, 等於HttpReponseMessage*/
                              myRespModel responseMsg =  JsonConvert.DeserializeObject<myRespModel>(restResponse.Content);
      
                              if (responseMsg.OK )
                              {
                                  string fm ;
                                  /*把Web API回傳的亂數檔案名稱用Json格式回傳到Browser*/
                                  fm = JsonConvert.DeserializeObject<IEnumerable<string>>(responseMsg.Message).FirstOrDefault();
                                  filesList.Add(fm);                                                                                        
                              }
                              else
                              {
                                  throw new Exception();
                              }
                          }
                      }
                  }
                  catch
                  {
                      filesList = null;
                  }
                  /*把Web API回傳的亂數檔案名稱回傳到Browser*/
                  return JsonConvert.SerializeObject(filesList);
              }
      
              /*讀取檔案*/
              public byte[] ReadToEnd(Stream stream)
              {
                  long originalPosition = stream.Position;
                  stream.Position = 0;
      
                  try
                  {
                      byte[] readBuffer = new byte[4096]; /*最大上傳檔案size*/
      
                      int totalBytesRead = 0;
                      int bytesRead;
      
                      while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                      {
                          totalBytesRead += bytesRead;
      
                          if (totalBytesRead == readBuffer.Length)
                          {
                              int nextByte = stream.ReadByte();
                              if (nextByte != -1)
                              {
                                  byte[] temp = new byte[readBuffer.Length * 2];
                                  Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                                  Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                                  readBuffer = temp;
                                  totalBytesRead++;
                              }
                          }
                      }
      
                      byte[] buffer = readBuffer;
                      if (readBuffer.Length != totalBytesRead)
                      {
                          buffer = new byte[totalBytesRead];
                          Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                      }
                      return buffer;
                  }
                  finally
                  {
                      stream.Position = originalPosition;
                  }
              }
          }
      }
      
      
  2. Browser的部分
    1. html的部分
      • <input type="file" name="UploadFiles" id="UploadFiles"  multiple />
            
        
        <input name="HiddenUploadFiles" id="HiddenUploadFiles" type="hidden" value
        hidden field是用來接收從Web Server回傳回來的亂數檔案名稱
    2. Javascript的部分
      • $('#UploadFiles').on('change', function (e) {
            var files = e.target.files;
            if (window.FormData !== undefined) {
                var data = new FormData();
                for (var x = 0; x < files.length; x++) {
                    data.append("file" + x, files[x]);
                }
        
                $.ajax({
                    type: "POST",
                    url: 'WebServer位置/Files/Upload',
                    contentType: false,
                    processData: false,
                    data: data,
                    success: function (result) {
                        dataType: 'application/json; charset=utf-8',
                        $('#HiddenUploadFiles').val(result);
                    },
                    error: 
                        console.log('err');
                    }
                });
            } else {
                alert("不支援");
            }
        })
總結:
Web API和Web Service最大的差異是Web API大量使用Http協定,所以習慣寫web service的人像我經常會搞混兩種做法。

小弟後來試過自己產生multi-part/formdata,可是實在有點麻煩所以放棄了。

Popular posts from this blog

[SQL SERVER] 找出LOCK方法懶人包

[SQL Server] 解決log檔(ldf file)過度膨脹的實戰經驗

[Windows7] 跨距磁碟區, 等量磁碟區, 鏡像磁碟區之區別