題目讀來有點不知所云,用實例講解才會清楚。在ASP.NET MVC Controller端建立的物件,想在輸出View的同時轉成JavaScript端物件,最直覺的做法是將物件轉為JSON字串,再以Razor語法內嵌一段var dataItem = { "num_prop": 1234, "str_prop": "ABCD", "bool_prop": true }; JavaScript語法,直接建立JavaScript物件。

但這個做法遇上DateTime屬性會有個小問題,例如:

public ActionResult Edit() 
{ 
    var item = new ColorData() 
    { 
        Index = 255, 
        Name = "Dark", 
        ConvTime = DateTime.Now, 
        Rank = 1, 
        RGBCode = "#000000", 
        Remark = "Very very dark..." 
    }; 
    ViewBag.DataItem = JsonConvert.SerializeObject(item); 
    return View(); 
}

View Edit.cshtml寫成:

<script> 
    var DataItem = @Html.Raw(ViewBag.DataItem); 
</script>

得到結果為:

var DataItem = {"Index":255,"Name":"Dark","RGBCode":"#000000",
    "ConvTime":"2016-06-28T21:09:15.2008013+08:00","Rank":1,
    "Remark":"Very very dark..."}; 

JavaScript的ConvTime屬性型別為字串,而我們期望的是Date型別。JavaScript端要將ISO 8601格式字串轉Date型別,最常見做法是在JSON.parse()時傳入DateReviver函式。依此概念衍生出兩種解法:

  • 將DataItem以JSON.stringify先轉成JSON字串,再用JSON.parse()+DateReviver轉回物件
  • 改寫為ViewBag.DataItemJson = JsonConvert.SerializeObject(JsonConvert.SerializeObject(item))跟
    var DataItemJson = "@Html.Raw(ViewBag.DataItemJson)";
    改傳字串到View端後再用JSON.parse()+DateReviver轉為物件

方法雖然可行,為了解決日期問題,JSON轉來轉去,怎麼看都有點蠢。心想,如果產生JSON時,用new Date(nnnn)取代"yyyy-MM-ddTHH:mm:ssZ",不靠游擊手轉傳,表演從全壘打牆邊直傳本壘的雷射肩,這才叫帥氣。

查了資料,Json.NET不虧是天神級的JSON兵器,有個JavaScriptDateTimeConverter可以協助我們實現願望。在SerializeObject時傳入new JavaScriptDateTimeConverter()當參數: 

public ActionResult Edit() 
{ 
    var item = new ColorData() 
    { 
        Index = 255, 
        Name = "Dark", 
        ConvTime = DateTime.Now, 
        Rank = 1, 
        RGBCode = "#000000", 
        Remark = "Very very dark..." 
    }; 
    ViewBag.DataItem = JsonConvert.SerializeObject(item, 
        new JavaScriptDateTimeConverter()); 
    return View(); 
}

2021-01-07 補充:若 JSON 內容可能包含 HTML 標籤,需啟用 StringEscapeHandling.EscapeHtml 設定以避免 XSS 風險參考

JSON字串中的ConvTime屬性值由ISO 8601格式字串會被改成new Date(nnnn),拿來宣告JS物件就直接是Date型別囉!

又到了呼口號時間:

Json.NET好威呀!


Comments

Be the first to post a comment

Post a comment