再談Jquery Ajax方法傳遞到action

以前寫過一篇文章Jquery Ajax方法傳值到action,本文是對該文的補充。html

假設 controller中的方法是以下: jquery

  
  
           
  
  
  1. public ActionResult ReadPerson(PersonModel model)  
  2.         {  
  3.             string s = model.ToString();  
  4.             return Content(s);  
  5.         } 
  6.  
  7. public ActionResult ReadPersons(List<PersonModel> model)  
  8.         {  
  9.             string result = "";  
  10.             if (model == nullreturn Content(result);  
  11.             foreach (var s in model)  
  12.             {  
  13.                 result += s.ToString();  
  14.                 result += "-------------";  
  15.             } 
  16.             return Content(result);  
  17.         } 

 其中PersonModel定義以下: ajax

  
  
           
  
  
  1. public class PersonModel  
  2.     {  
  3.         public int id  
  4.         {  
  5.             set;  
  6.             get;  
  7.         }  
  8.         public string name  
  9.         {  
  10.             set;  
  11.             get;  
  12.         } 
  13.  
  14.         public int age  
  15.         {  
  16.             set;  
  17.             get;  
  18.         } 
  19.  
  20.         public bool gender  
  21.         {  
  22.             set;  
  23.             get;  
  24.         }  
  25.         public string city  
  26.         {  
  27.             set;  
  28.             get;  
  29.         } 
  30.  
  31.         public override string ToString()  
  32.         {  
  33.             string s = string.Format(@"id:{0}  
  34. name:{1}  
  35. age:{2}  
  36. gender:{3}  
  37. city:{4}  
  38. ", id, name, age, gender, city);  
  39.             return s;  
  40.         }  
  41.     } 

那麼controller方法分別接受單個model和一個model的List。採用經過ajax傳遞參數。chrome

對於傳遞單個參數的狀況,假設js代碼以下: json

  
  
           
  
  
  1. var person = {  
  2.                id: "001",  
  3.                name: "zhangsan",  
  4.                age: "20",  
  5.                gender: true,  
  6.                city: "shanghai"  
  7.            }; 
  8.  
  9. var option = {  
  10.                url: '/test/ReadPerson',  
  11.                type: 'POST',  
  12. data: person,  
  13.                dataType: 'html',  
  14.                success: function (result) { alert(result); }  
  15.            };  
  16. $.ajax(option); 

 從chrome中截圖能夠看到以下:clipboard_thumb數組

傳遞的數據是一串Form數據,根據命名匹配的原則,也是能夠取得數據的。p_w_picpath_thumbapp


將option 的代碼改爲以下 ide

  
  
           
  
  
  1. var option = {  
  2.                url: '/test/ReadPerson',  
  3.                type: 'POST',  
  4.                data: JSON.stringify(person),  
  5.                dataType: 'html',  
  6.                success: function (result) { alert(result); }  
  7.            };  
  8. $.ajax(option); 

其中JSON.stringify方法簽名爲 stringify ( value [ , replacer [ , space ] ] ),根據ECMA-262標準stringify 函數返回的是JSON格式的字符串。它能夠有3個參數。摘抄以下:函數

The stringify function returns a String in JSON format representing an ECMAScript value. It can take three parameters. The first parameter is required. The value parameter is an ECMAScript value, which is usually an object or array, although it can also be a String, Boolean, Number or null. The optional replacer parameter is either a function that alters the way objects and arrays are stringified, or an array of Strings and Numbers that acts as a white list for selecting the object properties that will be stringified. The optional space parameter is a String or Number that allows the result to have white space injected into it to improve human readability.jsonp

默認的ContentType的屬性值是"application/x-www-form-urlencoded"

引自http://www.w3.org/TR/html401/interact/forms.html#adef-enctype

看請求頭的截圖:

clipboard[4]_thumb

所以,傳遞到controller的是一個json字符串,MVC根據命名匹配也是能夠得到到參數的值。


將將option 的代碼改爲以下

  
  
           
  
  
  1. var option = {  
  2.                 url: '/test/ReadPerson',  
  3.                 type: 'POST',  
  4.                 data: person,  
  5.                 dataType: 'html',  
  6.                  contentType: 'application/json',  
  7.                  success: function (result) { alert(result); }  
  8.                 };  

把contentType改爲json格式,那麼獲得的是出錯的信息。

雖然person是json對象,可是jquery中的ajax,data會自動的被轉換成查詢字符串格式key1=value1&key2=value2這種形式,很顯然這種形式不是json格式,所以會出錯。

要避免轉換成查詢字符串格式,只須要設置processData爲fasle便可。processData默認是true。

這裏須要注意的是:當指定了contentType的時候,數據將再也不按照Form Data的形式提交了,而是變成Request Data的形式提交。能夠從圖上的Request Header中看出。須要注意的是,Form Data提交的數據能夠由FormCollection得到到。Request Data方式提交的則不能經過FormCollection得到。

若是把processData設置爲默認值true。

p_w_picpath_thumb[3]

若是把processData設置爲false。

p_w_picpath_thumb[2]

以上兩種方式,按照application/json的類型傳給都會失敗,由於json是基於文本的格式,上面兩種方式傳遞的都不是json文本。所以會出錯。


所以,把option改爲:

  
  
           
  
  
  1. var option = {  
  2.     url: '/test/ReadPerson',  
  3.     type: 'POST',  
  4.     data:JSON.stringify(person),  
  5.     dataType: 'html',  
  6.     contentType: 'application/json',  
  7.     success: function (result) { alert(result); }  
  8. };  

則傳遞的就是json文本,所以根據命名匹配,就能得到值了。

clipboard[8]_thumb


對於較爲簡單是數據類型,有時候不指定contentType也能經過命名匹配傳值。可是對於稍微複雜點的數據類型,有時指定contentType: 'application/json',處理起來更加方便。

若是一個controller裏的action方法是接受一個List類型的參數,好比:

public ActionResult ReadPersons(List<PersonModel> model)

那麼js中先構造這樣的一個json對象的數組。以下

  
  
           
  
  
  1. var persons = [{ 
  2.                 id: "001"
  3.                 name: "zhangsan"
  4.                 age: "20"
  5.                 gender: true
  6.                 city: "shanghai" 
  7.             }, 
  8.             { 
  9.                 id: "002"
  10.                 name: "lisi"
  11.                 age: "21"
  12.                 gender: false
  13.                 city: "beijing" 
  14.             } 
  15.             ]; 

單純一個數組傳遞是做爲data傳遞是,Form Data也是沒法識別出的。所以把這個數組再次組成一個json形式。以下:其中json的鍵值用model是爲了能和controller中的參數名相同,能夠匹配。 

  
  
           
  
  
  1. var jsonp = { model: persons }; 
  2.            var option = { 
  3.                url: '/test/ReadPersons'
  4.                type: 'POST'
  5.                data: jsonp, 
  6.                dataType: 'html'
  7.                success: function (result) { alert(result); } 
  8.            }; 

因爲未指定contentType,所以是默認的application/x-www-form-urlencoded。此時是按照Form Data的方式傳遞的,

clipboard

能夠從截圖中看到。可是這種格式的數據,controller中只能得到指定model用2個元素,沒法得到元素中屬性的值。

clipboard[1]

若是把data改爲JSON.stringify(jsonp),以下:     

  
  
           
  
  
  1. var option = { 
  2.               url: '/test/ReadPersons'
  3.               type: 'POST'
  4.               data: JSON.stringify(jsonp), 
  5.               dataType: 'html'
  6.               success: function (result) { alert(result); } 
  7.           };  

clipboard[2]

那麼傳遞過去的Form Data是一串字符串,controller跟沒法識別出這個東西,所以獲不到值。若是僅僅設置contentType: 'application/json',而傳遞的又不是json格式的數據,以下:

  
  
           
  
  
  1. var option = { 
  2.     url: '/test/ReadPersons'
  3.     type: 'POST'
  4.     data: jsonp, 
  5.     dataType: 'html'
  6.     contentType: 'application/json'
  7.     success: function (result) { alert(result); } 
  8. }; 

由於jquery的ajax方法會把data轉換成查詢字符串,所以就變成以下的樣子。這串文本固然不符合json格式,所以會出現下面的錯誤。

clipboard[3]

clipboard[4]

若是設置contentType: 'application/json',而且設置data: JSON.stringify(persons),以下:

  
  
           
  
  
  1. var option = { 
  2.                 url: '/test/ReadPersons'
  3.                 type: 'POST'
  4.                 data: JSON.stringify(persons), 
  5.                 dataType: 'html'
  6.                 contentType: 'application/json'
  7.                 success: function (result) { alert(result); } 
  8.             }; 

那麼能夠得到到真正完整的json數據了

clipboard[5]


最後,此處再演示一個更復雜的參數類型,以便加深理解。

首先看一下Controller中的方法簽名,TestClassB 和一個TestClassA的List。稍顯複雜。 

  
  
           
  
  
  1. public ActionResult Fortest(TestClassB TB,List<TestClassA> TA) 
  2.         { 
  3.             string result = ""
  4.             return Content(result); 
  5.         } 

再看TestClassA和TestClassB,更顯複雜。可是結構要清晰的話,也不是很難。

  
  
           
  
  
  1. public class TestClassA 
  2.     { 
  3.        public string a1 { setget; } 
  4.        public List<string> a2 { setget; } 
  5.     } 
  6.     public class TestClassB 
  7.     { 
  8.         public string b1 { setget; } 
  9.         public InnerTestClassC ITCC { setget; } 
  10.         public class InnerTestClassC 
  11.         { 
  12.             public List<int> c1 { setget; } 
  13.         } 
  14.     } 

看js代碼:逐步的構造出一個json格式。

  
  
           
  
  
  1. $("#btn").click(function () { 
  2.             var jsondata = { TB: {}, TA: [] }; 
  3.             jsondata.TB.b1 = "b1"
  4.             jsondata.TB.ITCC = {}; 
  5.             jsondata.TB.ITCC.c1 = new Array(1, 2, 3, 4); 
  6.             var ta1 = {}; 
  7.             ta1.a1 = "a1"
  8.             ta1.a2 = new Array("a""b""x""y"); 
  9.            var ta2 = {}; 
  10.             ta2.a1 = "a2"
  11.             ta2.a2 = new Array("a2""b2""x2"); 
  12.             jsondata.TA.push(ta1); 
  13.             jsondata.TA.push(ta2); 
  14.             var option = { 
  15.                 url: '/test/Fortest'
  16.                 type: 'POST'
  17.                 data: JSON.stringify(jsondata), 
  18.                 dataType: 'html'
  19.                 contentType: 'application/json'
  20.                 success: function (result) { alert(result); } 
  21.             }; 
  22.             $.ajax(option); 
  23.         }); 

最終,發送出去的json字符串以下:

{"TB":{"b1":"b1","ITCC":{"c1":[1,2,3,4]}},"TA":[{"a1":"a1","a2":["a","b","x","y"]},{"a1":"a2","a2":["a2","b2","x2"]}]}

Controller接收到這個json串後,就能自動的匹配參數了。具體獲得的參數以下截圖:

clipboard[6]

clipboard[7]


總結:

1.不指定contentType的話,默認都是application/x-www-form-urlencoded方式發送。此時即使發送的是json格式的數據,默認狀況下,jquery的ajax也會把他轉爲查詢字符串的形式(能夠經過修改ajax參數修改),以FormData的形式發送出去。

2.不指定contentType的時候,若是controller中的方法簽名比較簡單,那麼即使是FormData形式的數據也能由MVC的命名匹配規則獲取到數據。

3.指定contentType爲'application/json'時候,發送的數據必須是符合json規範的字符串。一般,使用 JSON.stringify(jsondata)有較好的可讀性,能夠得到一個json字符串。固然,不是必須的。使用拼接的字符串,只要是符合json規範的,也是能夠發送的。

4.若是contentType爲'application/json'時,發送的data不是符合json規範的字符串,則會出錯。

5.一般狀況下,儘可能指定contentType爲'application/json',而且發送json字符串做爲發送數據,這樣可讀性更好,而且對於複雜的函數簽名,也能起到很好的匹配。

相關文章
相關標籤/搜索