2014年3月10日 星期一

ASP.NET MVC 4 WebApi 與 Extjs 的結合 -- 一個Form同時上傳Data與File

在閱讀此文章前,請先參考
ASP.NET MVC 4 WebApi 與 Extjs 的結合 -- 送出表單 ( Submit Form )
ASP.NET MVC 4 WebApi 與 Extjs 的結合 -- 動態複製表單並送出
ASP.NET MVC 4 WebApi 與 Extjs 的結合 -- 上傳檔案 ( FileUpload )

為了避免網路或其他因素造成只成功上傳某些資料,所以需要將Form跟File上傳到同一個WebApi做資料儲存

同時上傳資料與檔案,Controller無法自動區分Form跟File丟到指定的Model裡面,所以我們需要對傳上來的資料做處理。
每次傳上來的資料類別不同,做成共用的Method讓大部分的狀況都可以直接使用,而且自動轉成我們所指定的型別。

先把Request.Form傳進去,用Keys跑迴圈把Value放到Dictionary去,因為我們需要自動轉換型別,先把Dictionary轉成Json格式,然後讓JsonConvert.DeserializeObject<T>去幫我們做型別轉換的處理。
備註:Key跟欄位名稱要一樣,多的Key不會被放到Model,沒有資料的欄位會是null。
public T getSingleFormData<T>(NameValueCollection Form)
{
  List<T> Data = new List<T>();
  Dictionary<string, object> tmpData = new Dictionary<string, object>();
  foreach (var item in Form.AllKeys)
  {
    tmpData.Add(item, Form[item]);
  }
  if (tmpData.Count > 0)
  {
    T formData = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(tmpData));
    Data.Add(formData);
  }
  return Data.FirstOrDefault();
}

看完單筆資料接收,當然有可能資料是多筆,這邊需要做傳過來的Key做切割,然後判斷這是第幾筆資料,所以要對AllKeys做排序,避免傳過來的順序亂掉導致轉換後是錯誤的資料。
public List<T> getMultiFormData<T>(NameValueCollection Form)
{
  List<T> Datas = new List<T>();
  Dictionary<string, object> tmpData = new Dictionary<string, object>();
  string Seq = string.Empty;
  foreach (var item in Form.AllKeys.OrderBy(x => x))
  {
    string[] formName = item.Split('.');
    string formSeq = formName[0].Substring(1, formName[0].Length - 2);
    if (string.IsNullOrEmpty(Seq) == false && Seq != formSeq)
    {
      if (tmpData.Count > 0)
      {
        T formData = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(tmpData));
        Datas.Add(formData);
      }
      tmpData.Clear();
    }
    Seq = formSeq;
    tmpData.Add(formName[1], Form[item]);
  }

  if (tmpData.Count > 0)
  {
    T formData = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(tmpData));
    Datas.Add(formData);
  }
  return Datas;
}

接下來做檔案的接收,因為直接把檔案存到資料庫,所以用Stream去存放。
public IDictionary<string, object> getFileData(HttpFileCollection Files)
{
  Dictionary<string, object> FilesStream = new Dictionary<string, object>();
  foreach (var item in Files.AllKeys)
  {
    HttpPostedFile File = Files[item];
    if (string.IsNullOrEmpty(File.FileName) == false)
    {
      Dictionary<string, object> tmpFile = new Dictionary<string, object>();
      tmpFile.Add("FileName", File.FileName);
      tmpFile.Add("Stream", File.InputStream);
      FilesStream.Add(item, tmpFile);
    }
  }
  return FilesStream;
}

Method都寫完,開始動手寫資料處理的部分。
public HttpResponseMessage Post()
{
  var httpRequest = HttpContext.Current.Request;
  //多筆
  List<Products> AllProducts = getMultiFormData<Products>(httpRequest.Form);
  /*
  Code
  */

  //單筆
  Products Products = getSingleFormData<Products>(httpRequest.Form);
  /*
   Code
   */

  //檔案
  IDictionary<string, object> Files = getFileData(httpRequest.Files);
  foreach (var item in Files)
  {
    Dictionary<string, object> tmpFile = (Dictionary<string, object>)item.Value;
   /*
    Code
    */
  }
  return Request.CreateResponse(HttpStatusCode.OK);
}

David Kuo
為什麼要傳參數,而不在Method直接取Request?

答:
如果從Method直接取Request,這樣不夠彈性,變成其他NameValueCollection、HttpFileCollection的資料要取就會沒辦法使用,然後也有可能在建立共用物件時發生Request未初始化的問題。
參考:
ASP.NET MVC 4 Web Api 回傳HttpResponseMessage遇到 System.ArgumentNullException: Value cannot be null. Parameter name: request

沒有留言 :

張貼留言

Related Posts Plugin for WordPress, Blogger...