Model Binding是Asp .net Mvc裡面用來處理表單送出(Form Post)資料自動轉成強型別的機制。
  一般來說,如果用HtmlHelper產生的html內容,在Post back的時候Model Binding基本上不會遇到什麼問題。   
不過為了網站responsive更好,很多時候會希望Form Post是透過ajax來做。
這個時候依據不同做法,就很容易造成form post到asp .net mvc的時候Model Binding不到。
這篇將會建議不同情境的時候應該如何寫正確的Jquery Form post寫法,避免Model Binding不到的問題。
tag標註每一個不同的情境。   三種情境建議做法 - TL;DR
基本上要form post的時候會遇到三種不同的情況:
- 想Post的內容是所有的Form欄位 - 換句話說只是要ajax post模擬一個submit的效果
- 想post的內容只是表單裡面幾個欄位,並非全部的欄位
- 想Post的內容包含檔案上傳
針對這三個不同情境,有幾個不同的jquery post方式建議:
- 想Post的內容是所有的Form欄位
- 只需要post的時候, - data欄位傳入:- $("#postForm").serialize()即可。- 片段範例: - $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: $("#postForm").serialize() })
- 想post的內容只是表單裡面幾個欄位
- 組出最後要送出的javascript 物件 data
- 在 ajax 的 data欄位值輸入:JSON.stringify(data)
- 在 ajax的 contentType欄位值輸入:"application/json"
 - 片段範例: - var data = []; data.push({ Title: $("input[name='[0].Title']").val(), Content: $("input[name='[0].Content']").val() }); data.push({ Title: $("input[name='[1].Title']").val(), Content: $("input[name='[1].Content']").val() }); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: JSON.stringify(data), contentType: "application/json" })
- 組出最後要送出的javascript 物件 
- 想post的內容包含檔案上傳
-     可以使用FormData,注意,只有支援Html 5的browser才能夠用,所以IE 10 以下就不用考慮了。- 用Formhtmlelement 建立FormData- 例如:var data = new FormData($("#postForm")[0]);
- 在 ajax 的 data欄位值輸入第一步建立出來的data
- 在 ajax 的 processData欄位值輸入:false
- 在 ajax 的 contentType欄位值輸入:false
 片段範例: var data = new FormData($("#postForm")[0]); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: data, processData: false, contentType: false })
- 用
如果對於為什麼這三種情境是這樣建議有興趣,請往下看.....
三種情境做法建議原因
依照不同的情境,jquery post的呼叫方式其實也會需要不同不然到asp .net mvc model binding的時候很容易失敗,會話很多時間在debug這些問題,以下將會對於3個情境的做法進一步說明。
想Post的內容是所有的Form欄位
   一般來說,在建立Form表單的時候,撰寫上會使用HtmlHelper,這種產生出來的html內容只要post上去asp .net mvc model binding基本上沒有什麼問題。    
因此可以利用Form表單本身然後透過jquery序列化的方式作為送出的資料。
   假設我們的Form表單的id是postForm,那麼整個post方式就是:     
$.ajax({
 type: "POST",
 url: "@Url.Action("JqueryPost")",
 data: $("#postForm").serialize()
})   換句話說其實就是用jquery模擬一般的postsubmit。    
想post的內容只是表單裡面幾個欄位
   有時候要post的內容可能不全部在同一個Form表單,或者可能有幾個不同地方的欄位組成,這個時候,第一種情境的序列化做法就不適合了。    
   這個時候可能會想說建立一個javascript 物件,然後直接post這個物件。例如,假設後端要binding的model 有 Title和Content欄位:    
var data = {};
data.Title = "a";
data.Content = "b";
$.ajax({
 type: "POST",
 url: "@Url.Action("JqueryPost")",
 data: data
})這個會binding成功,因此可能想說都是這麼處理就好,但是,當要binding的物件比較複雜的時候,這個方式就會binding失敗。
舉例來說,假設我們有同樣的model結構,但是這個時候後台變成需要的是一個list,這個時候可能想說傳入array即可:
var data = [];
data.push({ Title: "1", Content: "2" });
data.push({ Title: "2", Content: "4" });
$.ajax({
 type: "POST",
 url: "@Url.Action("JqueryPost")",
 data: data
})但是這個會binding失敗,主要原因是因為預設jquery使用的是application/x-www-form-urlencoded作為ContentType - 這種方式的產生結構類似於querystring的那種串聯方式,因此在處理複雜結構 的時候產生出來的內容不符合asp .net mvc預設model binding的邏輯。 
因此建議直接傳送json格式的內容,在處理複雜結構沒有什麼問題。
不過要使用json格式的資料就會需要:
- 用JSON.stringfy()把物件轉成json的字串樣子
- 把ContentType設定成為:application/json- 告知mvc傳入的內容是json
因此整個範例變成:
var data = [];
data.push({ Title: "1", Content: "2" });
data.push({ Title: "2", Content: "4" });
$.ajax({
 type: "POST",
 url: "@Url.Action("JqueryPost")",
 data: SON.stringify(data),
 contentType: "application/json"
})- 範例程式碼,當object是單純的時候,直接post JavaScript 物件沒有問題:tag sample/jquery-simple-object-post
- 範例程式碼,當object是複雜物件的時候,直接post JavaScript物件有問題tag sample/jquery-complex-object-post-fail
- 範例程式碼,當object是複雜物件的時候,用json格式post - 建議方式tag sample/jquery-complex-object-post-sucess
想post的內容包含檔案上傳
當想要post上去的內容包含檔案上傳(input type="file")的時候,上述提到的2種做法都沒有辦法達成。
原因是因為檔案上傳要包含的資訊豐富很多,上述兩種方式都沒有辦法達到。
   因此當需要post的內容包含檔案上傳,需要使用特殊的資料類型FormData。    
FormData只有在支援Html 5的browser才有支援,因此IE 10 以下沒有辦法。       要使用FormData非常的簡單,只需要在new的時候傳入Form的html element物件即可。    
   有了FormData作為資料之後,還有兩個設定:    
- processData要設定為- false避免jquery傳送的時候有額外做一些處理
- 把ContentType設定為false讓jquery決定送出的類型
整個的範例如下:
var data = new FormData($("#postForm")[0]);
$.ajax({
 type: "POST",
 url: "@Url.Action("JqueryPost")",
 data: data,
 processData: false,
 contentType: false
})結語
越來越多網站會要求直接使用ajax - 整個畫面不需要post給使用者感官沒有load那麼久。
希望透過這篇能夠提供一個Reference,當要用jquery ajax post的時候,asp .net mvc model binding不到的時候可以參考以下,避免在抓頭了。
 
沒有留言 :
張貼留言