天天看點

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

1.1.1 摘要

Ajax技術的核心是XMLHttpRequest對象(簡稱XHR),可以通過使用XHR對象擷取到伺服器的資料,然後再通過DOM将資料插入到頁面中呈現。雖然名字中包含XML,但Ajax通訊與資料格式無關,是以我們的資料格式可以是XML或JSON等格式。

XMLHttpRequest對象用于在背景與伺服器交換資料,具體作用如下:

  • 在不重新加載頁面的情況下更新網頁
  • 在頁面已加載後從伺服器請求資料
  • 在頁面已加載後從伺服器接收資料
  • 在背景向伺服器發送資料

本文目錄

  • XMLHttpRequest的用法
  • Ajax同源請求
  • 同源政策與跨源政策
  • Ajax跨源請求

1.1.2 正文

XMLHttpRequest是一個JavaScript對象,它是由微軟設計,并且被Mozilla、Apple和Google采納,W3C正在标準化它。它提供了一種簡單的方法來檢索URL中的資料。

我們要建立一個XMLHttpRequest執行個體,隻需new一個就OK了:

Creates a XMLHttpRequest object.
var req = new XMLHttpRequest();      

也許有人會說:“這可不行啊!IE6不支援原始的XHR對象”,确實是這樣,我們在後面将會介紹支援IE6或更老版本建立XHR對象的方法。

XMLHttpRequest的用法

在建立XHR對象後,接着我們要調用一個初始化方法open(),它接受五個參數具體定義如下:

void open(
   DOMString method, //"GET", "POST", "PUT", "DELETE"
   DOMString url,
   optional boolean async,
   optional DOMString user,
   optional DOMString password
);      

通過上面的定義我們知道open()方法的簽名包含五個參數,其中有參數method和url位址是必填的,假設我們針對URL: myxhrtest.aspx發送GET請求擷取資料,具體定義如下:

var req = new XMLHttpRequest();

req.open(
    "GET",
    "myxhrtest.aspx",
    false
);      

通過上述代碼會啟動一個針對myxhrtest.aspx的GET請求,這裡有兩點要注意:一是URL相對于執行代碼的目前頁面(使用絕對路徑);二是調用open()方法并不會真正發送請求,而隻是啟動一個請求準備發送。

隻能向同一個域中使用相同端口和協定的URL中發送請求;如果URL與啟動請求的頁面有任何差别,都會引發安全錯誤。

要真正發送請求要使用send()方法,send()方法接受一個參數,即要作為請求主體發送的資料,如果不需要通過請求主體發送資料,我們必須傳遞一個null值。在調用send()之後,請求就會被分派到伺服器,完整Ajax請求代碼如下:

var req = new XMLHttpRequest();

req.open(
    "GET",
    "myxhrtest.aspx",
    false
);
req.send(null);      

在發送請求之後,我們需要檢查請求是否執行成功,首先可以通過status屬性判斷,一般來說,可以将HTTP狀态代碼為200作為成功标志。這時,響應主體内容會儲存到responseText中。此外,狀态代碼為304表示請求的資源并沒有被修改,可以直接使用浏覽器緩存的資料,Ajax的同步請求代碼如下:

if (req != null) {
    req.onreadystatechange = function() {

        if ((req.status >= 200 && req.status < 300) || req.status == 304) {
             Do something.
        }
        else {
            alert("Request was unsuccessful: " + req.status);
        }
    };
    req.open("GET", "www.myxhrtest.aspx", true);
    req.send(null);
}      

前面我們定義了Ajax的同步請求,如果我們發送異步請求,那麼在請求過程中javascript代碼會繼續執行,這時可以通過readyState屬性判斷請求的狀态,當readyState = 4時,表示收到全部響應資料,屬性值的定義如下:

readyState值 描述
未初始化;尚未調用open()方法
1 啟動;尚未調用send()方法
2 已發送;但尚未收到響應
3 接收;已經收到部分響應資料
4 完成;收到全部響應資料

表1 readyState屬性值

同步請求:發生請求後,要等待伺服器執行完畢才繼續執行目前代碼。

異步請求:發生請求後,無需等到伺服器執行完畢,可以繼續執行目前代碼。

現在我們要增加判斷readyState屬性值,當readyState = 4時,表示全部資料接收完成, 是以Ajax的異步請求代碼如下:

if (req != null) {
    req.onreadystatechange = function() {

         Checks the asyn request completed or not.
        if (req.readyState == 4) {
            if ((req.status >= 200 && req.status < 300) || req.status == 304) {
                 Do something.
            }
            else {
                alert("Request was unsuccessful: " + req.status);
            }
        }
    };
    req.open("GET", "www.myxhrtest.aspx", true);
    req.send(null);
}      

Ajax同源請求

現在我們對Ajax的請求實作有了初步的了解,接下來我們将通過具體的例子說明Ajax請求的應用場合和局限。

在日常網絡生活中,我們在浏覽器的位址中輸入要通路的URL并且回車,浏覽器會向伺服器發送請求,當伺服器收到請求後,把相應的請求頁面發送回浏覽器,我們會發現頁面大部分加載完畢,有些還沒有加載完畢。總得來說,采用異步加載方式不會影響已加載完畢的頁面浏覽,我們可以通過Ajax實作異步加載。

這裡我們以AdventureWorks資料庫為例,把産品表(Product)中的資料通過報表呈現給使用者,我們可以通過多種方法實作該報表需求,這裡我們将通過Ajax實作該功能。

首先,我們要把背景資料轉換為JSON格式,接下來我們定義Product表的資料庫通路對象(DAO),具體的實作代碼如下:

/// <summary>
/// The product datatable dao.
/// </summary>
public class ProductDao
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ProductDao"/> class.
    /// </summary>
    public ProductDao()
    {
    }

    /// <summary>
    /// Gets or sets the product id.
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// Gets or sets the product name.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Gets or sets the product serial number.
    /// </summary>
    public string SerialNumber { get; set; }

    /// <summary>
    /// Gets or sets the product qty.
    /// </summary>
    public short Qty { get; set; }
}      

前面我們定義了Product表的資料庫通路對象——ProductDao,它包含四個屬性分别是産品的Id,名稱,序列号和銷售數量。

接下來,讓我們實作Product表的資料庫操作類。

/// <summary>
/// Product table data access manager.
/// </summary>
public class ProductManager
{
    /// <summary>
    /// The query sql.
    /// </summary>
    private const string Query = 
        "SELECT ProductID, Name, ProductNumber, SafetyStockLevel FROM Production.Product";

    /// <summary>
    /// Stores the object of <see cref="ProductDao"/> into list.
    /// </summary>
    private IList<ProductDao> _products = new List<ProductDao>();

    /// <summary>
    /// Gets all products in product table.
    /// </summary>
    /// <returns>
    /// The list of <see cref="ProductDao"/> object.
    /// </returns>
    public IList<ProductDao> GetAllProducts()
    {
        using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN"].ToString()))
        using (var com = new SqlCommand(Query, con))
        {
            con.Open();
            using (var reader = com.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (reader.Read())
                {
                    var product = new ProductDao
                        {
                            Id = (int)reader["ProductID"],
                            Name = (string)reader["Name"],
                            SerialNumber = (string)reader["ProductNumber"],
                            Qty = (short)reader["SafetyStockLevel"]
                        };
                    _products.Add(product);
                }
            }
        }

        return _products;
    }
}      

前面我們實作了Product表的資料庫操作類——ProductManager,它包含兩個私有字段Quey和_products,還有一個擷取Product表中資料的方法——GetAllProducts()。

通過實作ProductDao和ProductManager,而且我們提供GetAllProducts()方法,擷取Product表中的資料,接下來我們要調用該方法擷取資料。

為了使資料通過JSON格式傳遞給頁面,這裡我們要建立一般處理程式(ASHX檔案),

一般處理程式适用場合:

  • 建立動态圖檔
  • 傳回REST風格的XML或JSON資料
  • 自定義HTML
Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖1一般處理程式

把一般處理程式檔案添加到項目中時,會添加一個擴充名為.ashx的檔案,現在我們建立一個一般處理程式ProductInfo,具體代碼如下:

<%@ WebHandler Language="C#" Class="ProductInfo" %>

using System.Runtime.Serialization.Json;
using System.Web;

using ASP.App_Code;

/// <summary>
/// The product data handler.
/// </summary>
public class ProductInfo : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {

        context.Response.ContentType = "application/json";

        // Creates a <see cref="ProductManager"/> oject.
        var manager = new ProductManager();

        // Invokes the GetAllProducts method.
        var products = manager.GetAllProducts();

        // Serializes data to json format.
        var json = new DataContractJsonSerializer(products.GetType());
        json.WriteObject(context.Response.OutputStream, products);
    }

    // Whether can resuable by other handler or not.
    public bool IsReusable {
        get {
            return false;
        }
    }
}      

大家注意到ProductInfo類實作了IHttpHandler接口,該接口包含一個方法ProcessRequest()方法和一個屬性IsReusable。ProcessRequest()方法用于處理入站的Http請求。在預設情況下,ProductInfo類會把内容類型改為application/json,然後我們把資料通過JSON格式寫入輸入流中;IsReusable屬性表示相同的處理程式是否可以用于多個請求,這裡我們設定為false,如果為了提高性能也可以設定為true。

如下圖所示,我們通過ProductInfo類成功地實作擷取資料到響應流中,并且以JSON格式顯示出來。

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖2 Http請求

當我們請求ProductInfo時, 首先它會調用ProcessRequest()方法,接着調用GetAllProducts()方法從資料庫中擷取資料,然後把資料通過JSON格式寫入到響應流中。

現在,我們已經成功地把資料通過JSON格式寫入到響應流當中,接着我們将通過Ajax方式請求資料并且把資料顯示到頁面中。

首先,我們定義方法createXHR()用來建立XMLHttpRequest對象,前面我們提到IE6或者更老的版本不支援XMLHttpRequest()方法來建立XMLHttpRequest對象,是以我們要在createXHR()方法中,增加判斷目前浏覽器是否IE6或更老的版本,如果是,就要通過MSXML庫的一個ActiveX對象實作。是以,在IE中可能遇到三種不同版本的XHR對象(MSXML2.XMLHttp6.0,MSXML2.XMLHttp3.0和MSXML2.XMLHttp)。

// Creates a XMLHttpRequest object bases on web broswer.
function createXHR() {

    // Checks whether support XMLHttpRequest or not.
    if (typeof XMLHttpRequest != "undefined") {
        return new XMLHttpRequest();
    }

    // IE6 and elder version.
    else if (typeof ActiveXObject != "undefined") {
        if (typeof arguments.callee.activeXString != "string") {
            var versions = [
        "MSXML2.XMLHttp6.0",
        "MSXML2.XMLHttp3.0",
        "MSXML2.XMLHttp"];

            for (var i = 0; i < versions.length; i++) {
                try {
                    var xhr = new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    return xhr;
                }
                catch (ex) {
                    throw new Error(ex.toString());
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        }
        else {
            throw new Error("No XHR object available");
        }

    }
    return null;
}

$(document).ready(function() {
    GetDataFromServer();
});      

前面我們定義了一個比較通用的方法用來建立XMLHttpRequest對象,并且它支援IE6或更老版本建立XMLHttpRequest對象,接下來我們将通過Ajax方法請求資料。

function GetDataFromServer() {

    // Creates a XMLHttpRequest object.
    var req = new createXHR();
      
    if (req != null) {
        req.onreadystatechange = function() {
            if (req.readyState == 4) {
                if ((req.status >= 200 && req.status < 300) || req.status == 304) {
                    alert(req.responseText);
                    var jsonTextDiv = document.getElementById("jsonText");

                    // Deserializes JavaScript Object Notation (JSON) text to produce a JavaScript value.
                    var data = JSON.parse(req.responseText);
                    for (var i = 0; i < data.length; i++) {
                        var item = data[i];
                        var div = document.createElement("div");
                        div.setAttribute("class", "dataItem");
                        // Inserts data into the html.
                        div.innerHTML = item.Name + " sold " + item.Qty + "; Product number: " + item.SerialNumber;
                        jsonTextDiv.appendChild(div);
                    }
                }
                else {
                    alert("Request was unsuccessful: " + req.status);
                }
            }
        };
        
        // Sends a asyn request. 
        req.open("GET", "ProductInfo.ashx", true);
        req.send(null);
    }
}      

由于前面我們介紹過Ajax發生請求的方法,是以不再重複介紹了,但我們注意到GetDataFromServer()方法中,擷取responseText資料(JSON格式),然後通過parse()方法把JSON格式資料轉換為Javascript對象,最後把資料插入到div中,頁面呈現效果如下:

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖3 Ajax請求結果

現在,我們成功地把資料輸出到頁面當中,也許使用者還會覺得使用者體驗不好,那麼我們給就該頁面增加CSS樣式。

由于時間的關系,我們已經把CSS樣式定義好了,具體如下:

#header {
    width: 100%;
    margin-left: 10px;
    margin-right: 10px;
    background-color:#480082;
    color: #FFFFFF;
}
body {
    margin-left: 40px;
    margin-right: 40px;
}
div#jsonText {
    background-color: #d9d9d9;
    -webkit-border-radius: 6px;
    border-radius: 6px;
    margin: 10px 0px 0px 0px;
    padding: 0px;
    border: 1px solid #d9d9d9;
}
div.dataItem {
    font-family: Verdana, Helvetica, sans-serif;
    color: #434343;
    padding: 10px;
}
div.dataItem:nth-child(2n) {
    background-color: #fafafa;
}
div.dataItem:first-child {
    -webkit-border-top-left-radius: 6px;
    -webkit-border-top-right-radius: 6px;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
}
div.dataItem:last-child {
    -webkit-border-bottom-left-radius: 6px;
    -webkit-border-bottom-right-radius: 6px;
    border-bottom-left-radius: 6px;
    border-bottom-right-radius: 6px;
}      

我們重新整理一下頁面,OK現在頁面效果好多了。

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖4 Ajax請求結果

同源政策與跨源政策

上面我們擷取頁面和資料都是在

同源請求

情況下,也就是說,用戶端浏覽器請求的頁面和資料都是屬于

同一域名

同一端口

同協定

同源政策:阻止從一個域上加載的腳本擷取或操作另一個域上的文檔屬性。也就是說,受到請求的URL的域必須與目前Web頁面的域相同、相同端口。這意味着浏覽器隔離來自不同源的内容,以防止它們之間的操作。

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖5同源請求過程

在一些情況下,我們不可以避免地要地需要從其他域名或伺服器中跨域請求資料,但前面提到Ajax隻能向同一個域中使用相同端口和協定的URL中發送請求;如果URL與啟動請求的頁面有任何差别,都會引發安全錯誤。

跨源政策(CORS):是一個Web浏覽器技術規範,它定義了一個方法讓Web伺服器允許其他域名頁面通路它的資源。跨源政策定義了一個方法讓浏覽器和伺服器可以互動決定是否允許跨源請求。

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖6跨源請求過程

大家注意到同源請求中我們使用的是JSON格式,但在跨源請求中卻是使用JSONP,這時大家可能有點困惑,坦然我剛開始學習的時候也是這樣的。

首先我們必須了解JSON和JSONP的差別:JSON是一種資料格式,而JSONP像是通過一個方法名來封裝JSON格式;由于浏覽器允許跨源請求<script>資源,如我們的HTML頁面代碼中使用了Google的jQuery庫,當我們Web程式發送跨源請求後,伺服器給我們提供響應資料,但伺服器無法預知接受JSON資料的方法名,是以我們要提供一個方法名。

Ajax跨源請求

跨域請求資料解決方案主要有如下解決方法:

  1. JSONP方式
  2. 表單POST方式
  3. 伺服器代理
  4. Html5的XDomainRequest
  5. Flash request

在介紹JSONP方式解決跨域請求資料之前,首先我們看看JSONP的定義。

JSONP(JSON with Padding)是一個非官方的協定,它允許在伺服器端內建Script tags傳回至用戶端,通過Javascript callback的形式實作跨域通路(這僅僅是JSONP簡單的實作形式)。

由于同源政策的限制,XMLHttpRequest隻允許請求目前源(域名、協定、端口)的資源,為了實作跨域請求,可以通過script标簽實作跨域請求,然後在服務端輸出JSON資料并執行回調函數,進而解決了跨域的資料請求。

假設部落格園提供一個API接口:http://www.cnblogs.com/hotblogs/json?,供開發者調用擷取熱門博文。

這裡我們可以通過兩種方式調用該接口:

1. 用Javascript定義回調函數

其實,通過Javascript定義回調函數調用該接口比較直覺,我們隻需告訴伺服器接收資料的方法名就OK了,比如:

http://www.cnblogs.com/hotblogs/json? callback=myFunction

其中myFunction是我們在頁面自定義的函數用來接收伺服器回傳的資料,myFunction的定義如下:

// The call back function.
function myFunction(data) {
    // Your code here.
}      

2. 使用jQuery的Ajax方法

假設我們想在部落格中增加顯示浪微網誌的公共微網誌資訊,我們可以在部落格中調用微網誌提供的API擷取跨源資料,接下來,我們将使用jQuery的Ajax方法擷取跨域資料。

首先,檢視微網誌API文檔找到了公共微網誌的API接口statuses/public_timeline 擷取最新的公共微網誌消息,它支援JSON或XML格式資料。

參數 必選 類型及範圍 說明
source true string 申請應用時配置設定的AppKey,調用接口時候代表應用的唯一身份。(采用OAuth授權方式不需要此參數)
count false int,預設值20,最大值200 每次傳回的記錄數
count false int,預設值20,最大值200 每次傳回的記錄數

表2請求參數

上面的請求參數隻有source(AppKey)是必須的,是以我們需要向微網誌申請AppKey,在調用API時,隻需把我們的AppKey傳遞給接口就OK了。

接下來讓我們看一下微網誌資料組成,這裡我們使用JSON viewer檢視微網誌的資料組成,具體資料如下:

Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖7微網誌JSON資料

通過上圖,我們知道微網誌的資料資訊很豐富,它是由一些基礎資料類型和複雜資料類型user組成的,接下來我們将使用jQuery實作調用微網誌接口方法。

首先,我們定義一個全局的對象,它包含三個屬性分别是:numWeibo、appendTo和appKey,還有三個方法loadWeibo()、timeAgo()和clean(),具體定義如下:

JQWeibo = {

     // The number of weibos display in the page.
     // Sets the number of weibos, append class and app key.
     numWeibo: 15,
     appendTo: '#jsWeibo',

     // The appkey you apply from weibo.
     appKey: YourAppKey,

     // The function to get weibo data.
     loadWeibo: function() {
     },

     /**
     * Convert the time to relative time.
     * @return {string} relative time like "8 minutes ago"
     */
     timeAgo: function(dateString) {
     },

     ify: {
         clean: function(weibo) {
             return this.hash(this.at(this.list(this.link(weibo))));
         }
     } // ify

};      

上面我們定義了一個對象JQWeibo,其中loadWeibo()方法使用jQuery的Ajax方法向微網誌API發送跨源請求,接下來讓我們實作該方法吧。

// The function to get weibo data.
loadWeibo: function() {
    $.ajax({
        // Weibo API.
        url: "http://api.t.sina.com.cn/statuses/public_timeline.json",
        type: "GET",
        dataType: "jsonp",
        data: {
            source: JQWeibo.appKey,
            count: JQWeibo.numWeibo
        },

        // When the requet completed, then invokes success function.
        success: function(data, textStatus, xhr) {

            // Sets html structure.
            var html =
            '<div class="weibo">' +
            '<a href="http://weibo.com/DOMAIN" target="_blank" rel="external nofollow"  target="_blank">USER</a>' +
            ':WEIBO_TEXT<div class="time">AGO</div>';

            // Appends weibos into html page.
            for (var i = 0; i < data.length; i++) {
                $(JQWeibo.appendTo).append(
                html.replace('WEIBO_TEXT', JQWeibo.ify.clean(data[i].text))

                // Uses regex and declare DOMAIN as global, if found replace all.
                    .replace(/DOMAIN/g, data[i].user.domain)
                    .replace(/USER/g, data[i].user.screen_name)
                    .replace('AGO', JQWeibo.timeAgo(data[i].created_at))
            );
            }
        }
    })
}      

現在,我們使用$.ajax()方法向微網誌API發送跨源請求,而且我們向API傳遞了JQWeibo.appKey和JQWeibo.numWeibo,當請求完成後,調用Success()方法把JSON資料插入的頁面當中。

頁面的HTML代碼如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Weibo Feed</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="css/WeiboFeed.css">
</head>
<body>
    <div id="jsWeibo"></div>
</body>
</html>      
Ajax與JSON的一些總結1.1.1 摘要1.1.2 正文1.1.3 總結

圖8 跨源資料

如上圖所示,我們使用$.ajax()方法調用公共微網誌接口,當成功擷取伺服器回調資料插入到我們的頁面當中。

1.1.3 總結

本文主要介紹了Ajax在同源請求适用性,但在跨源請求中其存在的局限性,進而介紹Ajax和JSONP在跨源請求下解決方法。

回答qianlifeng關于跨源請求的幾個問題:

1.一般的跨源不用jsonp請求為什麼會報錯?和同源的不都是一個請求麼?(可能對ajax了解不深)

答:首先跨源請求的解決方法不僅僅有JSON,本文中提及了其他方法,如:表單POST方式、伺服器代理、Html5的XDomainRequest和Flash request等;而你提到報錯,我覺得你首先要确認資料格式是否正确。關于跨原請求和同源請求本文已經給出了介紹。

2.關于“用Javascript定義回調函數”那塊看的不是很明白。傳遞目前頁面的一個js方法給跨源伺服器,為什麼就能跨源請求了呢?(JSONP?) 服務端根據這個js方法做了什麼操作啊?

答:首先我們了解JSON是一種資料格式,而JSONP像似通過一個方法名來封裝JSON格式;而跨源請求不是說指定一個回調函數實作的,而是我們利用了浏覽器允許跨源請求<script>資源,你也可以我的HTML代碼中使用的是Google提供的jQuery庫,這也說明了<script>資源可以跨源請求。當我們發送跨源請求後,伺服器會傳回JSONP,但伺服器無法預知接受JSON資料的方法名,所有我們要把函數名告訴(傳遞)伺服器。

//JSON 
{"name":"JK_Rush","id":23} 
//JSONP 
func({"name":"JK_Rush","id":23});       

3.看你新浪微網誌的那個例子,是jquery的ajax對跨源做了處理?能不能說說您提到的兩種跨源方式的差別或者不同的應用場景,還是随便都一樣?

答:是通過$.ajax()方法實作的,如果你想使用動态Javascript實作也可以;至于兩種跨源的差別已經在博文中指出了。

回答@On the road....關于JSON反序列化為對象的實作:

答:一般我們可以通過三種方法把JSON資料反序列化為對象,分别是:ASP.NET AJAX中引入的JavaScriptSerializer,WCF中引入的DataContractJsonSerializer,以及Json.NET。

假設,我們擷取到員工資訊(employee)的JSON資料,它包含兩個屬性分别是id和複雜屬性name,具體如下所示:

[
  {
    "id": "82105",
    "name": {
      "lastName": "Huang",
      "firstName": "JK"
    }
  },
  {
    "id": "82106",
    "name": {
      "lastName": "Leung",
      "firstName": "Cindy"
    }
  }
]

string data = "[{\"id\":\"82105\",\"fullname\":{\"lastName\":\"Huang\",\"firstName\":\"JK\"}}," + 
    "{\"id\":\"82106\",\"fullname\":{\"lastName\":\"Leung\",\"firstName\":\"Cindy\"}}]";      

根據上述JSON資料的組成,我們定義出相應的對象模型,具體定義如下:

// The Employee model.
public class Employee
{
    public int Id { get; set; }
    public Name FullName { get; set; }
}

// The Name model.
public class Name
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}      

接下來,我們将介紹使用JavaScriptSerializer,Json.NET和DataContractJsonSerializer反序列化JSON資料為對象。

JavaScriptSerializer

var serializer = new JavaScriptSerializer();
var employees= serializer.Deserialize<Employee[]>(data);      

Json.NET

using (var stringReader = new StringReader(data))
using (var jsonTextReader = new JsonTextReader(stringReader))
{
    var serializer = new JsonSerializer();
    var employees = serializer.Deserialize<Employee[]>(jsonTextReader);
}      

DataContractJsonSerializer

對于使用WCF的DataContractJsonSerializer方法,我們需要在對象模型添加DataContract和DataMember屬性,具體定義如下:

[DataContract]
public class Employee
{
    [DataMember(Name = "id")]
    public int Id { get; set; }

    [DataMember(Name = "fullname")]
    public Name FullName { get; set; }
}

[DataContract]
public class Name
{
    [DataMember(Name = "firstName")]
    public string FirstName { get; set; }

    [DataMember(Name = "lastName")]
    public string LastName { get; set; }
}      

接着我們使用ReadObjects()方法把JSON資料轉換為對象。

using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(data))) 
{ 
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Employee>));
    var employee = (List<Employee>)serializer.ReadObject(ms); 
}      

參考

  • https://developer.mozilla.org/en/XMLHttpRequest
  • http://www.w3schools.com/xml/xml_http.asp
  • http://msdn.microsoft.com/en-us/library/windows/apps/cc836466%28v=vs.85%29.aspx
  • http://ntesmailfetc.blog.163.com/blog/static/206287061201241011546581/
  • http://justcoding.iteye.com/blog/1366102
  • http://www.queness.com/post/8567/create-a-dead-simple-twitter-feed-with-jquery