Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 為現任微軟最有價值專家 (MVP)、微軟認證講師 (MCT) 、Blogger、Youtuber:記錄軟體開發的點點滴滴 著重於微軟技術、C#、ASP .NET、Azure、DevOps、Docker、AI、Chatbot、Data Science

[jquery]jquery ajax post能夠正確Model Bind到Asp .net Mvc網站 - 三種不同情境的建議做法

2017-09-30 Saturday
image
圖片來源:https://pixabay.com/en/key-tag-security-label-symbol-2114047/

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不到的問題。

這篇文章相關的範例程式碼在:https://github.com/alantsai-samples/aspnetmvc-jquery-post-model-binding-sample,有用tag標註每一個不同的情境。

三種情境建議做法 - TL;DR

基本上要form post的時候會遇到三種不同的情況:

  1. 想Post的內容是所有的Form欄位 - 換句話說只是要ajax post模擬一個submit的效果
  2. 想post的內容只是表單裡面幾個欄位,並非全部的欄位
  3. 想Post的內容包含檔案上傳

針對這三個不同情境,有幾個不同的jquery post方式建議:

想Post的內容是所有的Form欄位

只需要post的時候,data欄位傳入:$("#postForm").serialize() 即可。

片段範例:

$.ajax({
 type: "POST",
 url: "@Url.Action("JqueryPost")",
 data: $("#postForm").serialize()
})
想post的內容只是表單裡面幾個欄位
  1. 組出最後要送出的javascript 物件 data
  2. 在 ajax 的 data欄位值輸入:JSON.stringify(data)
  3. 在 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"
})
想post的內容包含檔案上傳
可以使用FormData,注意,只有支援Html 5的browser才能夠用,所以IE 10 以下就不用考慮了。
  1. Form htmlelement 建立 FormData - 例如:var data = new FormData($("#postForm")[0]);
  2. 在 ajax 的 data 欄位值輸入第一步建立出來的data
  3. 在 ajax 的 processData欄位值輸入:false
  4. 在 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"
})

想post的內容包含檔案上傳

當想要post上去的內容包含檔案上傳(input type="file")的時候,上述提到的2種做法都沒有辦法達成。

原因是因為檔案上傳要包含的資訊豐富很多,上述兩種方式都沒有辦法達到。

因此當需要post的內容包含檔案上傳,需要使用特殊的資料類型FormData

FormData只有在支援Html 5的browser才有支援,因此IE 10 以下沒有辦法。

要使用FormData非常的簡單,只需要在new的時候傳入Form的html element物件即可。

有了FormData作為資料之後,還有兩個設定:

  1. processData要設定為false避免jquery傳送的時候有額外做一些處理
  2. 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不到的時候可以參考以下,避免在抓頭了。


如果文章對您有幫助,就請我喝杯飲料吧
街口支付QR Code
街口支付QR Code
台灣 Pay QR Code
台灣 Pay QR Code
Line Pay 一卡通 QR Code
Line Pay 一卡通 QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
2017-09-30 Saturday
comments powered by Disqus