Json傳遞對象集合 JSON.net使用

大綱
(1)初識JSON
(2)在ASP.NET中使用JSON
(3)NET 2.0 使用JSON.net 進行反序列化
(4)Newtonsoft.Json處理日期問題
(5)JSON修飾標籤,日期序列化
(6)JSON集合序列化
(7)JSON回調方法修飾標籤
(8)JSON序列化錯誤處理


(1)初識JSON
本篇介紹JSON的基礎知識。在沒有接觸AJAX之前我還不知道什麼是JSON,在讀Jeffrey Zhao的《深入Atlas系列》時纔看到這個詞,所以有必要了解一下JSON。這裏我結合今天初淺的認識及一個小練習記錄我的學習。
JSON是什麼?
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。易於人閱讀和編寫。同時也易於機器解析和生成。它基於JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一個子集。 JSON採用完全獨立於語言的文本格式,但是也使用了類似於C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。這些特性使JSON成爲理想的數據交換語言。
JSON建構於兩種結構:
1)“名稱/值”對的集合(A collection of name/value pairs)。不同的語言中,它被理解爲對象(object),紀錄(record),結構(struct),字典(dictionary),哈希表(hash table),有鍵列表(keyed list),或者關聯數組(associative array)。
2)值的有序列表(An ordered list of values)。在大部分語言中,它被理解爲數組(array)。
這些都是常見的數據結構。事實上大部分現代計算機語言都以某種形式支持它們。這使得一種數據格式在同樣基於這些結構的編程語言之間交換成爲可能。
有關JSON的更多介紹,訪問它的官方網站:http://www.json.org
用 JSON 表示如下:
{"city":"Beijing","street":" Chaoyang Road ","postcode":100025}
其中 Value 也可以是另一個 Object 或者數組,因此,複雜的 Object 可以嵌套表示,例如,一個 Person 對象包含 name 和 address 對象,可以表示如下:
{"name":"Michael","address": {"city":"Beijing","street":" Chaoyang Road ","postcode":100025}}
(2)在ASP.NET中使用JSON
Json.NET的簡單介紹
首先介紹一個爲方便在.NET中使用JSON的API,Json.NET。它方便我們讀取從瀏覽器流向服務器的JSON對象,也方便在響應流中寫入JSON對象。這裏下載:Json.NET。
Json.NET只提供了服務器端的方法,主要有實現JSON文本與XML互相轉換的類,有自定義讀寫JSON的JsonReader類和JsonWriter類,還有一個非自定義讀寫JSON的JavaScriptSerializer類。
ASP.NET AJAX中,服務器端由JavaScriptSerializer類的幾個方法來用於實現序列化和反序列化能力。在Json.NET中,服務器端的序列化和反序列化能力則主要由JavaScriptConvert類的幾個方法提供。本篇的例子只使用了JavaScriptConvert。
贈人玫瑰,手留餘香。 2
csAxp
JavaScriptConvert
Json.NET中,這個類用於序列化和反序列化JavaScript對象。
這個類有兩個方法:
序列化
SerializeObject(object value, params JsonConverter[] converters),
它有個重載方法SerializeObject(object value)
反序列化
DeserializeObject(string value, Type type),
它有個重載方法DeserializeObject(string value)
(3)NET 2.0 使用JSON.net 進行反序列化
大家知道 JSON.net 最新版是基於.net 3.5 框架的,要如何使其工作在 .NET 2.0框架下呢,當然是GOOGLE + baidu 啦,幸不辱命,終於在一篇英文的博客中找到了解決方法,
這篇文章的大概意思就是
首先下載最新版的JSON.NET 源碼(http://json.codeplex.com/),然後解壓,SRC目錄是其源碼,我們打開Newtonsoft.Json.Net20.sln,這個是.NET 2.0的解決方案,然後編譯,很順利的就通過了,反正我是沒遇啥特殊情況。編譯完成後在 bin\Release 目錄中你會看到一個名爲DotNet20 的目錄,很顯然這個JSON.net 的源碼做的相當不錯,已經爲我們寫好了在.NET2.0下運行的方法。你會發現這裏邊多了一個DLL文件(LinqBridge.dll),這個是做什麼用的呢? 在那編老外寫的文章中介紹說是在.NET2.0框架下的LINQ,反正我對這個LINQ也不怎麼熟,沒有管,說這個組件有用就有用吧,接下來COPY LinqBridge.dll 和Newtonsoft.Json.Net20.dll 到 Json35r8\Source\TOOLS\ILMerge 中。還差最後一步。打開CMD 窗口運行如下命令:
ilmerge.exe /internalize /out:Newtonsoft.Json.Net20.Merged.dll Newtonsoft.Json.Net20.dll LinqBridge.dll
這樣會將兩個DLL 合併爲一個DLL,在程序中將合併後的DLL引入,就可以使用最新版的JSON.NET 了
我的反序列化代碼:
代碼
public static IList<SearchResult> GetSearchList(string jsons)
我的反序列化代碼:
代碼
public static IList<SearchResult> GetSearchList(string jsons)
{
// get JSON result objects into a list
JObject o = (JObject)JsonConvert.DeserializeObject(jsons);
贈人玫瑰,手留餘香。 3
csAxp
JToken torrentsArray = (JToken)o["rules"];
// serialize JSON results into .NET objects
IList<SearchResult> searchResults = new List<SearchResult>();
SearchResult c = null;
foreach (JToken result in torrentsArray)
{
c = new SearchResult();
c.SearchField = result.SelectToken("field").ToString().Replace("\"","");
c.searchString = result.SelectToken("data").ToString().Replace("\"", "");
c.SearchOper = result.SelectToken("op").ToString().Replace("\"", "");
//Criterion searchResult = JsonConvert.DeserializeObject<Criterion>(result.ToString());
searchResults.Add(c);
}
return searchResults;
}
json:
{
"aaa":"bbbb",
"rules":[
{
"field":"xxxx",
"data":"ooooo",
"op":"lt"
},
{
"field":"xxxx",
"data":"ooooo",
"op":"gt"
},
{
"field":"xxyxx",
"data":"ooooo",
"op":"lte"
}
]
}
以下json.net 實例代碼網址:
http://www.java2s.com/Open-Source/CSharp/Development/Json.NET/Newtonsoft/Json/Tests/Serialization/JsonSerializerTest.cs.htm 贈人玫瑰,手留餘香。 4
csAxp
(4)Newtonsoft.Json處理日期問題
1)問題描述
用Newtonsoft.Json轉換json,可是如果數據庫是日期類型轉換出來之後變成了"\/Date(1269582661683+0800)\/"這樣的格式
2)解決方案
(1)使用IsoDateTimeConverter
//第一步:獲取數據
DataTable mDataTable = mDataSet.Tables[0];
//第二步:設置日期格式(使用自定義格式,如果不使用,默認是ISO8601格式)
IsoDateTimeConverter mTimeConverter = new IsoDateTimeConverter();
//第三步:轉換數據對象
strJosn=JsonConvert.SerializeObject(mDataTable, Formatting.Indented, mTimeConverter);
strJosn=JsonConvert.SerializeObject(mDataTable, mTimeConverter);
輸出結果:" LogDate": "2009-10-16 16:59:59"
(2)使用JavaScriptDateTimeConverter
//第一步:獲取數據
DataTable mDataTable = mDataSet.Tables[0];
//第二步:設置日期格式
JavaScriptDateTimeConverter mTimeConverter = new JavaScriptDateTimeConverter();
//第三步:轉換數據對象
strJosn=JsonConvert.SerializeObject(mDataTable, Formatting.Indented, mTimeConverter);
strJosn=JsonConvert.SerializeObject(mDataTable, mTimeConverter);
輸出結果:"LogDate": new Date(1269582661683)
//第四步:javascript中對數據進行格式處理
renderer: Ext.util.Format.dateRenderer('Y年m月d日')
輸出結果:2009年10月16日
3)注意事項
上面使用的IsoDateTimeConverter和JavaScriptDateTimeConverter類都是來至Newtonsoft.Json,所以在使用時,記得引用該插件(using Newtonsoft.Json、using Newtonsoft.Json.Converters)。
(5)JSON修飾標籤,日期序列化
1)
修飾標籤,日期序列化
(1)
通過屬性標籤自定義JSON序列化
JsonObjectAttribute:類修飾標籤,用於控制類如何被序列化爲一個json對象
JsonArrayAttribute:集合修飾標籤,用於控制集合如何被序列化爲一個json對象
JsonPropertyAttribute:域和屬性修飾標籤,用於控制它們如何被序列化爲一個json對象中的屬性
JsonConverterAttribute:類,域,屬性修飾標籤,用於指定序列化期間的轉換器
示例代碼:
贈人玫瑰,手留餘香。 5
csAxp
[JsonObject(MemberSerialization.OptIn)]
public class Customer
{
[JsonProperty(PropertyName="ID")]
public int Unid { get; set; }
[JsonProperty]
public string CustomerName { get; set; }
[JsonProperty]
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime CreateTime { get; set; }
[JsonProperty]
public string Memo { get; set; }
}
JsonObjectAttribute
這個標籤的成員序列化標誌指定成員序列化是opt-in(要序列化的成員必須帶有JsonProperty或DataMember標籤)還是opt-out(默認所有的都會序列化,但通過JsonIgnoreAttribute標籤可以忽略序列化。opt-out是json.net默認的)。
JsonPropertyAttribute
允許被序列化的成員自定義名字。這個標籤同時標示出:在成員序列化設置爲opt-in的時候,成員會被序列化。
JsonIgnoreAttribute
忽略域或屬性的序列化
JsonConverterAttribute
用於指派轉換對象的JsonSerializer。
這個標籤可以修飾類或類成員。用於修飾類時,通過此標籤指派的JsonConverter會被設置爲序列化類的默認方式。用於修飾屬性或域成員時,被指派的JsonConverter會序列化它們的值。
(2)
序列化日期
json中的日期是困難的。這個問題來源於json細則本身,因爲在json中沒有日期的原義句法。這個細則包括對象,數組,字符串,整型和浮點,但它沒有對日期定義相關的標準。在json.net中用於日期的默認的格式與微軟:“\/Date(1198908717056)\/”這
贈人玫瑰,手留餘香。 6
csAxp
個一樣。
DateTime JsonConverters
因爲在json中沒有關於日期的標準,在系統間的互操作過程中出現了大量不同的格式。幸運的是json.net提供了用於讀寫自定義日期格式的解決方案:JsonConverters。一個json轉換器用於指定一種類型如何被序列化。
public class LogEntry
{
public string Details { get; set; }
public DateTime LogDate { get; set; }
}
public void WriteJsonDates()
{
LogEntry entry = new LogEntry
{
LogDate = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc),
Details = "Application started."
};
string defaultJson = JsonConvert.SerializeObject(entry);
// {"Details":"Application started.","LogDate":"\/Date(1234656000000)\/"}
string javascriptJson = JsonConvert.SerializeObject(
entry, new JavaScriptDateTimeConverter());
// {"Details":"Application started.","LogDate":new Date(1234656000000)}
string isoJson = JsonConvert.SerializeObject(entry, new IsoDateTimeConverter());
// {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"}
}
JavaScriptDateTimeConverter
這個來自json.net的轉換器是兩種日期轉換器之一。它是把日期序列化爲一個js日期對象。
new Date(1234656000000)
IsoDateTimeConverter
這種轉換器把日期序列化爲一個ISO8601格式的字符串。
"2009-02-15T00:00:00Z"
這個類有一個日期格式化屬性,用於自定義其它的格式字符串。
(6)JSON集合序列化
Json序列化器支持大量序列化和反序列化集合對象的方法。
要序列化一個集合(泛型列表,字典或自定義集合),只需簡單的調用相關的序列
贈人玫瑰,手留餘香。 7
csAxp
化器就可以了。json.net會序列化這個集合和它包含的所有值。
1)
序列化
List<Customer> _list = new List<Customer>();
_list.Add(new Customer { Unid=1, CustomerName="宋江",Memo="天魁星"});
_list.Add(new Customer { Unid = 1, CustomerName = "吳用", Memo = "天機星" });
_list.Add(new Customer { Unid = 1, CustomerName = "石秀", Memo = "天慧星" });
string strJson = JsonConvert.SerializeObject(_list, Formatting.Indented);
/*
[{"ID": 1,"CustomerName": "宋江","Memo": "天魁星"},
{"ID": 1,"CustomerName": "吳用","Memo": "天機星"},
{"ID": 1,"CustomerName": "石秀","Memo": "天慧星"}]
*/
2)反序列化
反序列化一個json對象到一個.net集合,只需指定要反序列化的集合類型即可。json.net支持大量的集合類型。
string strJson = @"[{""ID"": 1,""CustomerName"": ""宋江"",""Memo"": ""天魁星""},{""ID"": 1,""CustomerName"": ""吳用"",""Memo"": ""天機星""},{""ID"": 1,""CustomerName"": ""石秀"",""Memo"": ""天慧星""}]";
List<Customer> _list = JsonConvert.DeserializeObject<List<Customer>>(strJson);
foreach (Customer c in _list)
{
Console.WriteLine(c.CustomerName);
}
/*
宋江
吳用
石秀
*/
3)反序列化字典
json.net也能把json對象反序列化爲一個泛型字典。json對象的屬性名和值會被添加到一個字典中。
string strJson = @"{""ID"": 1,""CustomerName"": ""宋江"",""Memo"": ""天魁星""}";
Dictionary<string, string> _dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(strJson);
贈人玫瑰,手留餘香。 8
csAxp
foreach (KeyValuePair<string, string> kp in _dictionary)
{
Console.WriteLine(kp.Key + ":" + kp.Value);
}
這裏還用這個例子,雖然這個例子沒有意義,但屬性與屬性值也可以看做一個字典關係。
(7)JSON回調方法修飾標籤
2)
序列化回調方法修飾標籤
json.net支持序列化回調方法標籤。一個回調修飾標籤可以在序列化和反序列化對象前後控制對象。
OnSerializing
OnSerialized
OnDeserializing
OnDeserialized
通知序列化器在對象的序列化生命週期內要調用哪些方法,並用適合的標籤來修飾方法(序列化時,序列化後,反序列化時,反序列化後)。
參考類:Customer
public class Customer
{
//在序列化前後沒有變動
public int Unid { get; set; }
//在序列化前後設置和重置
public string CustomerName { get; set; }
//設置爲null,但在序列化後填充
public string Memo { get; set; }
//忽略序列化,OnDeserializedAttribute標籤用於序列化之後設置一個值
[JsonIgnore]
public string Other { get; set; }
public Customer()
{
Unid = 11;
CustomerName = "宋江";
Other = "忽略序列化";
Memo = null; 贈人玫瑰,手留餘香。 9
csAxp
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
CustomerName = "在序列化時被寫入數據文件";
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
CustomerName = "序列化之後被賦值";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Other = "反序列化時被賦值";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Memo = "反序列化之後,被賦值";
}
}
這個.net類有4個屬性:
·Unid,在序列化前後值沒有變化,且值不爲null
·CustomerName,在序列化前後賦值和重設值
·Memo,給null值
·Other,這個屬性忽略序列化。
public void SerializeCallbacks()
{
Customer customer = new Customer();
Console.WriteLine(customer.Unid);
Console.WriteLine(customer.CustomerName);
Console.WriteLine(customer.Memo);
Console.WriteLine(customer.Other);
/*
11
宋江
贈人玫瑰,手留餘香。 10
csAxp
忽略序列化
*/
string json = JsonConvert.SerializeObject(customer, Formatting.Indented);
Console.WriteLine(json);
/*
{"Unid": 11,"CustomerName": "在序列化期間被寫入數據文件", "Memo": null}
*/
Console.WriteLine(customer.Unid);
Console.WriteLine(customer.CustomerName);
Console.WriteLine(customer.Memo);
Console.WriteLine(customer.Other);
/*
11
序列化之後被賦值
忽略序列化
*/
}
2)分析:
(1)在沒有序列化時的值
11
宋江
忽略序列化
輸出4個屬性的值,其中Memo值爲null
(2)序列化之後
{"Unid": 11,"CustomerName": "在序列化期間被寫入數據文件", "Memo": null}
·Unid在序列化之前和之後沒有變化
·CustomerName,在序列化之前設置爲“宋江”,但序列化之後變成了
“在序列化期間被寫入數據文件”([OnSerializing])
·Memo爲null值
·Other屬性被忽略
序列化之後:
·Customer對象的值:
11
序列化之後被賦值
忽略序列化
·Unid沒有變化
·CustomerName,序列化之後,被重新設置值“序列化之後被賦值”( [OnSerialized])
·Other,忽略序列化,值沒有變動
贈人玫瑰,手留餘香。 11
csAxp
(3)反序列化
接上
string json = JsonConvert.SerializeObject(customer, Formatting.Indented);
之後:
customer = JsonConvert.DeserializeObject<Customer>(strJson);
Console.WriteLine(customer.Unid);
Console.WriteLine(customer.CustomerName);
Console.WriteLine(customer.Memo);
Console.WriteLine(customer.Other);
/*
11
在序列化時被寫入數據文件
反序列化之後,被賦值
反序列化時被賦值 */
·Unid沒有變化
·CustomerName在序列化時,被賦值“在序列化期間被寫入數據文件”寫到數據文件(生成了json),即json對象中的CustomerName值爲“在序列化期間被寫入數據文件”,在反序列化之後,得到了CustomerName屬性爲這個值的對象
·Memo在反序列化之後被賦值爲“反序列化之後,被賦值” [OnDeserialized]標籤
·Other屬性在序列化時是被忽略的,而即使這樣,因爲[OnDeserializing]標籤的作用,使它在反序列化時被設定值“反序列化時被賦值”。
(8)JSON序列化錯誤處理
json.net支持序列化和反序列化錯誤處理。錯誤處理可以捕捉錯誤並且可以選擇處理錯誤且繼續序列化或把從程序中錯誤拋出。
定義錯誤處理有兩種方法:錯誤事件和錯誤修飾標籤。
1)
事件處理
List<string> errors = new List<string>();
List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(@"[
""2009-09-09T00:00:00Z"",
""不能轉換爲日期"",
[
1
],
""1977-02-20T00:00:00Z"",
null,
""2000-12-01T00:00:00Z""
]",
new JsonSerializerSettings
{
Error =delegate(object obj,Newtonsoft.Json.Serialization.ErrorEventArgs args)
{ 贈人玫瑰,手留餘香。 12
csAxp
errors.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
},
Converters ={new IsoDateTimeConverter()}
});
foreach (DateTime dd in c)
{
Console.WriteLine(dd.ToString());
}
泛型列表c是一個日期類型的集合,其中有3個值不能成功序列化。如果不添加錯誤事件處理,則序列化
出現錯誤。但通過錯誤事件處理,捕捉了其中的異常並使序列化繼續下去。
輸出結果:
/*
2009-9-9 0:00:00
1977-2-20 0:00:00
2000-12-1 0:00:00
*/
new JsonSerializerSettings
{
Error =delegate(object obj,Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
errors.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
},
Converters ={new IsoDateTimeConverter()}
});
在系列化設置中,添加錯誤事件處理:
·Error屬性是一個泛型委託:
EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs> fun =
delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
errors.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
};
贈人玫瑰,手留餘香。 13
csAxp
贈人玫瑰,手留餘香。 14
這個例子中把一個json反序列化爲一個日期集合。在序列化設置過程中爲錯誤事件分配一個處理器,這
個處理器用於記錄錯誤信息並且標記這些錯誤是經過處理的。
這個json反序列化的結果是:有3個反序列化的日期對象和3個錯誤信息,
·該字符串未被識別爲有效的 DateTime。有一個從索引 0 處開始的未知字。
·Unexpected token parsing date. Expected String, got StartArray.
·Cannot convert null value to System.DateTime.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章