設計 Ajax 習慣使用 jQuery 的 ajaxr功能,搭配 .NET 的 WebService 來提供資料,一般資料的傳遞並無問題,但由 WebService返回 DateTime 物件時, Client 端的 JSON(使用http://www.json.org/ 的 json2.js )無法完全轉成日期物件,而是字串,使得物件的序列/反序列不完全。
經追蹤測試,由WebService 回傳 (ObjectQuery<UserData> 一個Entity Framework 的資料表物件),在 return 時是否使 Serialize()進行序列化,會有不同結果
經追蹤測試,由WebService 回傳 (ObjectQuery<UserData> 一個Entity Framework 的資料表物件),在 return 時是否使 Serialize()進行序列化,會有不同結果
ID: 帳號 (String)
PWD:密碼(String)
Unit: 所屬單位(String)
Authorize:層級(String)
Name: 姓名((String)
ModifiedDate:資料更動日期(DateTime)
CreatedDate: 資料建立日期(DateTime)
FailedLoginCount:登入失敗次數紀錄(int)
LastLoginDate:最近一次成功登入日期 (DateTime)
LastFailedLoginDate:最近一次登入失敗日期(DateTime)
PWD:密碼(String)
Unit: 所屬單位(String)
Authorize:層級(String)
Name: 姓名((String)
ModifiedDate:資料更動日期(DateTime)
CreatedDate: 資料建立日期(DateTime)
FailedLoginCount:登入失敗次數紀錄(int)
LastLoginDate:最近一次成功登入日期 (DateTime)
LastFailedLoginDate:最近一次登入失敗日期(DateTime)
若在 ASP.NET 先經 JavaScriptSerializer.Serialize((ObjectQuery<UserData>)users) 進行序列化,則回傳 jQuery 字串為:
"{"d":"[{\"ID\":\"a\",\"PWD\":\"7367cc4cee061a476290d18978830414\",\"Unit\":\"資訊室\",\"Authorize\":\"1\",\"Name\":\"aA\",\"ModifiedDate\":\"\\/Date(1217994242220)\\/\",\"CreatedDate\":\"\\/Date(1217992404960)\\/\",\"FailedLoginCount\":null,\"LastLoginDate\":null,\"LastFailedLoginDate\":null,\"EntityState\":2,\"EntityKey\":{\"EntitySetName\":\"UserData\",\"EntityContainerName\":\"DraftEntities\",\"EntityKeyValues\":[{\"Key\":\"ID\",\"Value\":\"a\"}],\"IsTemporary\":false}}]"}"
jquery於ajax完成後,如果成功,則 success:function(reqObj) 會自動調用 JSON.parse(reqObj)對回傳資料進行剖析後(注意:.Net 的真正資料是存在 reqObj.d裡),所以在變成下列「字串」,必須再將 JSON.parse()處理一次。
reqObj.d="[{"ID":"a","PWD":"7367cc4cee061a476290d18978830414","Unit":"資訊室","Authorize":"1","Name":"aA","ModifiedDate":"\/Date(1217994242220)\/","CreatedDate":"\/Date(1217992404960)\/","FailedLoginCount":null,"LastLoginDate":null,"LastFailedLoginDate":null,"EntityState":2,"EntityKey":{"EntitySetName":"UserData","EntityContainerName":"DraftEntities","EntityKeyValues":[{"Key":"ID","Value":"a"}],"IsTemporary":false}}]"
但因為就算重新 parse,日期部分仍為字串 「/Date(1217994242220)/」, Client端必須另行對日期欄進行處理 eval(result[i].LastLoginDate.replace('/','"')) 才能真正得到 javascript 的日期物件。
asp.net允許物件不經過JavaScriptSerializer.Serialize(物件) 序列化,而直接回傳 (ObjectQuery<UserData>)users 物件的字串,
"{"d":[{"__type":"WebTemplate.Shared.UserData","ID":"a","PWD":"7367cc4cee061a476290d18978830414","Unit":"資訊室","Authorize":"2","Name":"aA","ModifiedDate":"\/Date(1217994242220)\/","CreatedDate":"\/Date(1217992404960)\/","FailedLoginCount":null,"LastLoginDate":null,"LastFailedLoginDate":null,"EntityState":2,"EntityKey":{"EntitySetName":"UserData","EntityContainerName":"DraftEntities","EntityKeyValues":[{"Key":"ID","Value":"a"}],"IsTemporary":false}}]}"
"/Date(1217992404960)/"
如果再將返回之物件傳給 JSON.parse() 剖析,會產生錯誤(例外事件)
由上面的結果可知,不論 .Net 端是否經過序列化(Serialize)過程,經由 jQuery ajax 取得回傳的物件,其中日期物件部分,皆以"\Date(nnnnn)\" 之字串型式回傳
為了解決這個問題,最徹底的方法就是改寫 json2.js,修正說明如下:(我取得的版本是 2011-10-19)
一、原程式的 462-465 行,是用來判斷字串是不是可以轉換成 javascript 物件:
if (/^[\],:{}\s]*$/ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
而 472 行就是利用 eval 將字串轉成 物件。
j = eval('(' + text + ')');
二、所以我們要修改這裡的程式,使其可將 /Date(nnnnn) / 轉成 new Date(nnnn)
首先,原始由 .Net 回傳的日期在字串的為
\"\\/Date(nnnnn)\\/\" (經過 序列化)首先,原始由 .Net 回傳的日期在字串的為
或
"\/Date(nnnnn)\/" (直接物件回傳)
所以我們在丟給 eval 之前要先將上面的字串內容換成 new Date(nnnnn),於是我在 461 行,加入了:
text = text.replace(/(\\\"\\\\\/){1}(Date\(\d*\)){1}(\\\\\/\\"\\){1}/g, "new $2") .replace(/(\"\\\/){1}(Date\(\d*\)){1}(\\\/\"){1}/g, "new $2");
但加了這一行之後,只要有日期物件傳入,就會引發例外,原來 new Date(nnnnn) 無法通過上述 462 - 465 的 test ,因此還還修改462 - 465 的程式碼,如下列藍字部分:
if (/^[\],:{}\s]*$/ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') .replace(/new Date\([0-9]*\)/ig, '') .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
這樣就可以應付上列兩種日期字串格式。
三、 記得:在 .Net 端如果有進行 JavaScriptSerializer.Serialize()序列化,在Client端除了 jQuery自動調用 JSON.parse() 外,還必須在程式中進行一次 JSON.parse(retObj.d),才會得到真正的物件內容。如果.Net 沒有進行 JavaScriptSerializer.Serialize()序列化,就不須再一次 JSON.parse(retObj.d),不然會出錯!
** 此方法僅對 .Net 之回傳資料測試通過,其他程式語言未測試 ,不保證適用 **
** 此方法僅對 .Net 之回傳資料測試通過,其他程式語言未測試 ,不保證適用 **
XXX 為什麼 IE6 可以自動調用 parse,但在 IE8、FireFox 就是不行 ?????
原來 IE8 與 FireFox(11)已內建原生 JSON 程式,所以 jQuery 會直接調用原生的 JSON.parse,以致上面所述修改 json2.js 的功用皆失效,根本不會叫用 json2.js。
查看 json2.js 程式碼之 162 至 165 來var JSON; if (!JSON) { JSON = {}; }
即判斷如果已註冊 JSON 物件,則 json2 就不再註冊此功能,為了能使用上面針對日期物件修正的功能,只好把 163、165兩行註解掉,強制 jQuery 使用 jsons2.js 的 JSON 功能!
var JSON; // if (!JSON) { JSON = {}; //}
相關文章:JSON.parse 無去剖析 .NET2 的JSON 日期
修改後之下載(zip檔) json2.cmj.js
沒有留言:
張貼留言