ASP.NET MVC的JSON序列化陷阱

转自:http://blog.darkthread.net/post-2012-08-29-aspnet-mvc-json-serializer.aspx

在ASP.NET MVC中,可透過以下方式將物件轉為JSON字串傳給前端:

public ActionResult TestJson() 

    return Json(DateTime.Now); 
}

而在ASP.NET Web API,Action多半會回傳特定資料型別,ApiController會依據呼叫端所要求將資料型別轉成XML(例如: 瀏覽器直接輸入URL)、JSON(例如: 使用$.getJSON())或其他格式[延伸閱讀]:

public class BarController : ApiController 

    public DateTime Index() 
    { 
        return DateTime.Now; 
    } 
}

ASP.NET MVC 4在上述傳回JSON的情境中,是用什麼類別進行JSON轉換呢?

答案: ASP.NET MVC 4用JavaScriptSerializer,而ASP.NET Web API從RC起己改用Json.NET? 讓我們來驗證一下。

開啟一個ASP.NET MVC 4空白專案,分別加入BooController及BarController:

BooController有兩個Action,Index()提供測試Web API專用的View、TestJson()則傳回JSON轉換後的DateTime: (在此型別特別選用DateTime,以便由輸出結果協助判斷背後的轉換核心為DataContractSerializer、JavaScriptSerializer或是Json.NET?)

排版顯示純文字

using System;

using System.Web.Mvc;

 

namespace MyMvc.Controllers

{

public class BooController : Controller

{

public ActionResult Index()

{

return View();

}

public ActionResult TestJson()

{

return Json(DateTime.Now, JsonRequestBehavior.AllowGet);

}

}

}

由於Web API直接以瀏覽器檢視會傳回XML,故在Index.cshtml中我們透過$.getJSON()來測試傳回內容:

排版顯示純文字

@{

Layout = null;

}

 

<!DOCTYPE html>

 

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>Index</title>

<script src="~/Scripts/jquery-1.8.0.js"></script>

<script>

$(function () {

$(":button").click(function () {

$.getJSON("@Url.Content("~/Api/Bar")", {}, function (r) {

alert(r);

});

});

});

</script>

</head>

<body>

<input type="button" value="Test Web API" />

</body>

</html>

BarController是一個Web API Controller,在Index() Action中傳回DateTime型別:

排版顯示純文字

using System;

using System.Web.Http;

 

namespace MyMvc.Controllers

{

public class BarController : ApiController

{

public DateTime Index()

{

return DateTime.Now;

}

}

}

程式完成後,開始測試。首先使用瀏覽器真接測試Web API BarController,在地址列輸入URL,因屬GET動作,故經過Content Neogociation後傳回XML: 

為了一睹Web API傳回的JSON內容,Boo/Index.cshtml透過$.getJSON()取得結果,該格式與Json.NET的日期轉換結果一致: 

接著測試Json(DateTime.Now),由"\/Date(Tick)\/"研判,其使用的是JavaScriptSerializer:(如為DataContractSerializer,會再加上時區資訊) 

既然是JavaScriptSerializer,就得留意使用JavaScriptSerializer反序列化後出現時區差異的鳥問題,用一段程式讓這顆地雷現形:

排版顯示純文字

public ActionResult DateJsonWtf()

{

WebClient wc = new WebClient();

Uri url = Request.Url;

string s = wc.DownloadString(

string.Format("http://{0}:{1}/Boo/TestJson",

url.Host, url.Port));

JavaScriptSerializer jss = new JavaScriptSerializer();

DateTime d = jss.Deserialize<DateTime>(s);

return Content(string.Format(

"Now={0:MM-dd HH:mm}, TestJson={1:MM-dd HH:mm}",

DateTime.Now, d));

}

果不其然,由ASP.NET MVC Action接收Json()序列化後的DateTime.Now再使用JavaScriptSerializer還原,得到的時間是UTC格林威治時間,與本機時間產生了8小時的時差! 在做類似應用時要特別小心。

至於是否有簡便的解決方案? 且待下回分解。

你可能感兴趣的:(mvc,json)