一般當用到大的Json文檔的時候,你可能只對其中的一小個片斷信息感興趣。這種狀況下你想把Json.Net轉換爲.Net 對象就會讓人很困擾,由於你必須爲Json的整個結果定義一個.Net的類。javascript
使用Json.Net很容易避開這個問題。在把它們傳遞到Json.Net序列化器以前,你可使用Linq to Json 提取Json中你想要序列化的一些片斷。html
string googleSearchText = @"{
""responseData"": {
""results"": [
{
""GsearchResultClass"": ""GwebSearch"",
""unescapedUrl"": ""http://en.wikipedia.org/wiki/Paris_Hilton"",
""url"": ""http://en.wikipedia.org/wiki/Paris_Hilton"",
""visibleUrl"": ""en.wikipedia.org"",
""cacheUrl"": ""http://www.google.com/search?q=cache:TwrPfhd22hYJ:en.wikipedia.org"",
""title"": ""<b>Paris Hilton</b> - Wikipedia, the free encyclopedia"",
""titleNoFormatting"": ""Paris Hilton - Wikipedia, the free encyclopedia"",
""content"": ""[1] In 2006, she released her debut album...""
},
{
""GsearchResultClass"": ""GwebSearch"",
""unescapedUrl"": ""http://www.imdb.com/name/nm0385296/"",
""url"": ""http://www.imdb.com/name/nm0385296/"",
""visibleUrl"": ""www.imdb.com"",
""cacheUrl"": ""http://www.google.com/search?q=cache:1i34KkqnsooJ:www.imdb.com"",
""title"": ""<b>Paris Hilton</b>"",
""titleNoFormatting"": ""Paris Hilton"",
""content"": ""Self: Zoolander. Socialite <b>Paris Hilton</b>...""
}
],
""cursor"": {
""pages"": [
{
""start"": ""0"",
""label"": 1
},
{
""start"": ""4"",
""label"": 2
},
{
""start"": ""8"",
""label"": 3
},
{
""start"": ""12"",
""label"": 4
}
],
""estimatedResultCount"": ""59600000"",
""currentPageIndex"": 0,
""moreResultsUrl"": ""http://www.google.com/search?oe=utf8&ie=utf8...""
}
},
""responseDetails"": null,
""responseStatus"": 200
}";
JObject googleSearch = JObject.Parse(googleSearchText);
// get JSON result objects into a list
IList<JToken> results = googleSearch["responseData"]["results"].Children().ToList();java
// serialize JSON results into .NET objects
IList<SearchResult> searchResults = new List<SearchResult>();
foreach (JToken result in results)
{
SearchResult searchResult = JsonConvert.DeserializeObject<SearchResult>(result.ToString());
searchResults.Add(searchResult);
}web
// Title = <b>Paris Hilton</b> - Wikipedia, the free encyclopedia
// Content = [1] In 2006, she released her debut album...
// Url = http://en.wikipedia.org/wiki/Paris_Hilton編程
// Title = <b>Paris Hilton</b>
// Content = Self: Zoolander. Socialite <b>Paris Hilton</b>...
// Url = http://www.imdb.com/name/nm0385296/json
爲了解決多餘的Json這個問題,Json.Net有一系列內置的選項能夠進行調整。數組
->JsonIgnoreAttribute and DataMemberAttribute瀏覽器
默認狀況下,在Json建立的時候Json.Net會包含全部類級別的public屬性和字段。添加JsonIgnoreAttribute到屬性上,告訴序列化器序列化時跳過它。框架
public class Car
{
// included in JSON
public string Model { get; set; }
public DateTime Year { get; set; }
public List<string> Features { get; set; }編程語言
// ignored
[JsonIgnore]
public DateTime LastModified { get; set; }
}
若是類有不少屬性,你只想序列化它的一小部分,添加JsonIgore到全部其餘的屬性上會比較冗餘,也比較容易出錯。有一種用來處理這種狀況的方法,添加DataContractAttribute到類上,添加DataMemberAttribute到須要被序列化的屬性上。與使用JsonIgnoreAttribute的opt-out序列化相比,opt-in序列化僅僅你標記的屬性被需列化。
using System.Runtime.Serialization;
[DataContract]
public class Computer
{
// included in JSON
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal SalePrice { get; set; }
// ignored
public string Manufacture { get; set; }
public int StockCount { get; set; }
public decimal WholeSalePrice { get; set; }
public DateTime NextShipmentDate { get; set; }
}
->Formatting
Json序列化時,用可選參數Formatting.Indented生成良好的顯示格式,可讀性更好。另外一方面,Formatting.None會跳過沒必要要的空格和換行符,讓Json的結果更小。生成的顯示格式更加緊湊,也許效率更高。
->NullValueHandling
在序列化器中NullVlaueHandling是可選的。它控制序列化器如何處理值爲null的屬性。經過設置NullValueHandling.Ignore值,序列化器會跳過值爲null的屬性。
public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> ReleaseCountries { get; set; }
}
測試1:
Movie movie = new Movie();
movie.Name = "Bad Boys III";
movie.Description = "It's no Bad Boys";
string included = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { });
Console.WriteLine(included);
輸出結果:
{
"Name": "Bad Boys III",
"Description": "It's no Bad Boys",
"Classification": null,
"Studio": null,
"ReleaseDate": null,
"ReleaseCountries": null
}
測試2:
string ignored = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
Console.WriteLine(ignored);
輸出結果:
{
"Name": "Bad Boys III",
"Description": "It's no Bad Boys"
}
NullValueHandling也能夠在單獨的屬性上用JsonPropertyAttribute進行定製。使用JsonPropertyAttribute時設置的NullValueHandling值會在Json序列化器中爲該屬性進行重寫。
->DefaultValuehandling
在序列化器中DefaultValuehandling是可選的。它控制序列化器如何處理帶有默認值的屬性。經過設置DefaultValuehandling.Ignore值,序列化器會跳過帶有默認值的屬性。對於引用類型爲null,對於值類型,如int和DateTime,序列化器將跳過默認未初使化值的值類型。
Json.Net也容許你經過DefaultValueAttribute自定義默認值,例如:若是一個字符串類型的屬性Department在它的默認狀態下老是返回一個空字符,可是在你的Json對象中你不想要那個空字符串,你能夠在Department上使用空字符串參數標記DefaultValueAttribute,這意味着Department在序列化時再也不寫入Json中,除非它有非空值。
public class Invoice
{
public string Company { get; set; }
public decimal Amount { get; set; }
// false is default value of bool
public bool Paid { get; set; }
// null is default value of nullable
public DateTime? PaidDate { get; set; }
// customize default values
[DefaultValue(30)]
public int FollowUpDays { get; set; }
[DefaultValue("")]
public string FollowUpEmailAddress { get; set; }
}
測試1:
Invoice invoice = new Invoice
{
Company = "Acme Ltd.",
Amount = 50.0m,
Paid = false,
FollowUpDays = 30,
FollowUpEmailAddress = string.Empty,
PaidDate = null
};
string includedDefaultValue = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { });
Console.WriteLine(includedDefaultValue);
輸出結果:
{
"Company": "Acme Ltd.",
"Amount": 50.0,
"Paid": false,
"PaidDate": null,
"FollowUpDays": 30,
"FollowUpEmailAddress": ""
}
測試2:
string ignoredDefaultValue = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
Console.WriteLine(ignoredDefaultValue);
輸出結果:
{
"Company": "Acme Ltd.",
"Amount": 50.0,
"Paid": false//??
}
DefaultValueHandling也能夠在單獨的屬性上用JsonPropertyAttribute進行定製。使用JsonPropertyAttribute時設置的DefaultValueHandling值會在Json序列化器中爲該屬性進行重寫。
->IContractResolver
爲了得到更多的靈活性,IContractResolver接口提供了定製.Net對象序列化爲Json的每個方面,包括在運行時改變序列化的行爲。
public class DynamicContractResolver : DefaultContractResolver
{
private readonly char _startingWithChar;
public DynamicContractResolver(char startingWithChar)
{
_startingWithChar = startingWithChar;
}
protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
{
IList<JsonProperty> properties = base.CreateProperties(contract);
// only serializer properties that start with the specified character
properties =
properties.Where(p => p.PropertyName.StartsWith(_startingWithChar.ToString())).ToList();
return properties;
}
}
public class Book
{
public string BookName { get; set; }
public decimal BookPrice { get; set; }
public string AuthorName { get; set; }
public int AuthorAge { get; set; }
public string AuthorCountry { get; set; }
}
測試:
Book book = new Book
{
BookName = "The Gathering Storm",
BookPrice = 16.19m,
AuthorName = "Brandon Sanderson",
AuthorAge = 34,
AuthorCountry = "United States of America"
};
string startingWithA = JsonConvert.SerializeObject(book, Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('A') });
Console.WriteLine(startingWithA);
// {
// "AuthorName": "Brandon Sanderson",
// "AuthorAge": 34,
// "AuthorCountry": "United States of America"
// }
string startingWithB = JsonConvert.SerializeObject(book, Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('B') });
Console.WriteLine(startingWithA);
// {
// "BookName": "The Gathering Storm",
// "BookPrice": 16.19
// }
IContractResolver接口提供了一種方法去定製序列化器如何去序列化和反序列化.Net對象爲Json對象
實現IContractResolver接口,而後爲Json序列化器分配一個實例對象,這樣你就能夠控制對象是否被序列化爲Json對象或者Json數組、對象的成員應該被序列化成什麼、如何被序列化、及他們被誰調用等。
->DefaultContractResolver
DefaultContractResolver是序列化器默認的解析器,它以虛函數的形式提供了不少擴展功能,能夠被覆寫(overriden).
->CamelCasePropertyNamesContractResolver
CamelCasePropertyNamesContractResolver繼承自DefaultContractResolver,而且簡單的覆寫了Json屬性名爲camel命名規則的形式(首字母小寫)
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public DateTime ExpiryDate { get; set; }
public string[] Sizes { get; set; }
}
測試:
Product product = new Product
{
ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
Name = "Widget",
Price = 9.99m,
Sizes = new[] { "Small", "Medium", "Large" }
};
string json = JsonConvert.SerializeObject(
product,
Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }
);
Console.WriteLine(json);
輸出結果:
{
"name": "Widget",
"price": 9.99,
"expiryDate": "\/Date(1292868060000)\/",
"sizes": [
"Small",
"Medium",
"Large"
]
CustomCreationConverter是一個在序列化過程當中提供自定方式去建立一個對象的Json轉換器,一旦對象被建立,它將被序列化器填充值。
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
DateTime BirthDate { get; set; }
}
public class Employee : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string Department { get; set; }
public string JobTitle { get; set; }
}
public class PersonConverter : CustomCreationConverter<IPerson>
{
public override IPerson Create(Type objectType)
{
return new Employee();
}
}
這是一個很是簡單的例子。更復雜的場景可能包含一個對象工廠或者服務定位器(service locator)用來在運行時解析這個對象。
測試:
string json = @"[
{
""FirstName"": ""Maurice"",
""LastName"": ""Moss"",
""BirthDate"": ""\/Date(252291661000)\/"",
""Department"": ""IT"",
""JobTitle"": ""Support""
},
{
""FirstName"": ""Jen"",
""LastName"": ""Barber"",
""BirthDate"": ""\/Date(258771661000)\/"",
""Department"": ""IT"",
""JobTitle"": ""Manager""
}
]";
List<IPerson> people = JsonConvert.DeserializeObject<List<IPerson>>(json, new PersonConverter());
IPerson person = people[0];
Console.WriteLine(person.GetType());// CustomCreationConverterTest.Employee
Console.WriteLine(person.FirstName);// Maurice
Employee employee = (Employee)person;
Console.WriteLine(employee.JobTitle);// Support
Json.Net支持在序列化和反序列化的過程當中進行異常處理。異常處理讓您捕獲一個異常,您能夠選擇是否處理它,繼續序列化或者讓異常拋給上一層,在你的應用程序中被拋出。
異常處理經過兩個方法來定義:the Error event on JsonSerializer 和 OnErrorAttribute
>Error Event
error event是一個創建在JsonSerializer 上的異常處理.當序列化或者反序列化JSON時,任何有異常拋出的狀況error event都會被觸發.就像創建在JsonSerializer上的全部設置同樣,它也能夠在JsonSerializerSettings 上進行設置從而傳遞給JsonConvert的序列化方法.
示例:
List<string> errors = new List<string>();
List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(@"[
""2010-12-19T00:00:00Z"",
""I am not a date and will error!"",
[
1
],
""2011-01-01T00:00:00Z"",
null,
""2010-12-25T00:00:00Z""
]", new JsonSerializerSettings()
{
Error = delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs e)
{
errors.Add(e.ErrorContext.Error.Message);
e.ErrorContext.Handled = true;
},
Converters = { new IsoDateTimeConverter() }
});
foreach (DateTime t in c)
{
Console.WriteLine(t.ToString());
}
//2010-12-19 00:00:00
//2011-01-01 00:00:00
//2010-12-25 00:00:00
foreach (string err in errors)
{
Console.WriteLine(err);
}
//The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.
//Unexpected token parsing date. Expected String, got StartArray.
//Cannot convert null value to System.DateTime.
在這個例子中咱們把一個Json數組反序列化爲一個DateTime的集合,在JsonSerializerSettings中有一個hander被賦值成了error event ,它用來記錄error message,並標記這個error爲已處理(handled).
反序列化JSON的結果是三個被成功反序列化的日期和三個error messages:一個是不正確的格式,"I am not a date and will error!",一個是嵌套了JSON數組,最後一個是null值,由於定義的list不容許有可空類型的DateTime.這個事件處理已經記錄了這些信息,Json.Net在序列化時繼續進行(沒有由於異常而中止),由於這些錯誤已經被標記爲已處理。
值得注意的是,在Json.Net進行異常處理時,沒有處理的異常將會被拋到上一層,並在它的每一個parent觸發事件,例如:在序列化若干對象的集合時,一個未處理的異常將被觸發兩次,首先在對象上,而後在集合上。這樣就會讓您在處理異常的時候,選擇在它發生的地方,或者是它的一個parent上。
若是您不是當即處理一個異常,僅僅是想針對它完成一次操做,您能夠驗證一下ErrorEventArg's CurrentObject是否等於OriginalObject.OriginalObject是拋出異常的對象,CurrentObject是事件被觸發的對象.他們只會在第一次(事件被OriginalObject觸發時)相等.
>OnErrorAttribute
OnErrorAttribute的工做方式很是像其餘Json.Net支持的.NET serialization attributes ,簡單地把它標記在帶有正確參數(一個StreamingContext和一個ErrorContext)的方法上就可使用了,與方法的名字沒有關係。
示例:
public class PersonError
{
private List<string> _roles;
public string Name { get; set; }
public int Age { get; set; }
public List<string> Roles
{
get
{
if (_roles == null)
throw new Exception("Roles not loaded!");
return _roles;
}
set { _roles = value; }
}
public string Title { get; set; }
[OnError]
internal void OnError(StreamingContext context, ErrorContext errorContext)
{
errorContext.Handled = true;
}
}
在這個例子中,當_roles沒有被設置值時訪問Roles屬性將會拋出一個異常.在序列化Roles屬性時,異常處理的方法將設置error爲handled,從而容許Json.Net繼續序列化這個類。
測試:
PersonError person = new PersonError
{
Name = "George Michael Bluth",
Age = 16,
Roles = null,
Title = "Mister Manager"
};
string json = JsonConvert.SerializeObject(person, Formatting.Indented);
Console.WriteLine(json);
輸出:
{
"Name": "George Michael Bluth",
"Age": 16,
"Title": "Mister Manager"
}
默認狀況下,Json.Net將經過對象的值來序列化它遇到的全部對象。若是工個list包含兩個Person引用,這兩個引用都指向同一個對象,Json序列化器將輸出每個引用的全部名稱和值。
定義類:
public class Person
{
public DateTime BirthDate { get; set; }
public DateTime LastModified { get; set; }
public string Name { get; set; }
}
測試:
Person p = new Person()
{
BirthDate = new DateTime(1985, 11, 27, 0, 0, 0, DateTimeKind.Utc),
LastModified = new DateTime(2010, 12, 20, 0, 0, 0, DateTimeKind.Utc),
Name = "James"
};
List<Person> people = new List<Person>();
people.Add(p);
people.Add(p);
string json = JsonConvert.SerializeObject(people, Formatting.Indented);
Console.WriteLine(json);
輸出結果:
[
{
"BirthDate": "\/Date(501897600000)\/",
"LastModified": "\/Date(1292803200000)\/",
"Name": "James"
},
{
"BirthDate": "\/Date(501897600000)\/",
"LastModified": "\/Date(1292803200000)\/",
"Name": "James"
}
]
在大多數狀況下這是指望的結果,可是在某些場景下,將list中的第二項做爲第一項的一個引用來輸出會是一個更好的解決方案。若是上面的Json如今被反序列化,返回的list會包含兩個徹底分離的對象,它們具備相同的值。經過值來輸出引用也會在對象上致使循環引用的發生。
>PreserveReferencesHandling
string json2 = JsonConvert.SerializeObject(people, Formatting.Indented,
new JsonSerializerSettings() { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
Console.WriteLine(json2);
輸出結果:
[
{
"$id": "1",
"BirthDate": "\/Date(501897600000)\/",
"LastModified": "\/Date(1292803200000)\/",
"Name": "James"
},
{
"$ref": "1"
}
]
List<Person> deserializedPeople = JsonConvert.DeserializeObject<List<Person>>(json2,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
Console.WriteLine(deserializedPeople.Count);// 2
Person p1 = deserializedPeople[0];
Person p2 = deserializedPeople[1];
Console.WriteLine(p1.Name);// James
Console.WriteLine(p2.Name);// James
bool equal = Object.ReferenceEquals(p1, p2);// true
在list中的第一個Person被序列化時增長了一個額外的對象Id,如今第二個Person對象僅僅是第一個的引用。
如今使用PreserveReferencesHandling後,在序列化時只建立了一個Person對象,list中包含它的兩個引用,原來咱們叫做反射(mirroring) 。
>IsReference on JsonObjectAttribute, JsonArrayAttribute and JsonPropertyAttribute
在對象序列化器上設置PreserveReferencesHandling,將會改變全部對象被序列化和反序列化的方式。爲了更加細緻地控制對象和成員被序列化爲一個引用,能夠在JsonObjectAttribute, JsonArrayAttribute 和 JsonPropertyAttribute上使用IsReference 屬性.
在JsonObjectAttribute, JsonArrayAttribute 上設置IsReference 爲true,意味着Json序列化器老是會序列這個類型爲一個引用。在JsonPropertyAttribute上設置IsReference爲true將只序列化這個屬性爲一個引用。
[JsonObject(IsReference = true)]
public class EmployeeReference
{
public string Name { get; set; }
public EmployeeReference Manager { get; set; }
}
測試:
List<EmployeeReference> empList = new List<EmployeeReference>();
empList.Add(empRef);
empList.Add(empRef);
string empRefJson = JsonConvert.SerializeObject(empList, Formatting.Indented);
Console.WriteLine(empRefJson);
輸出結果:
[
{
"$id": "1",
"Name": "IsReference",
"Manager": null
},
{
"$ref": "1"
}
]
>IReferenceResolver
要想定製引用的生成方式,能夠繼承自IReferenceResolver接口來使用Json序列化器。
Json序列化器爲序列化及反序列化集合對象提供了良好的支持.
->Serializing
爲了序列化一個集合---一個泛型的list,array,dictionary,或者自定義集合---簡單地調用序列化器,使用您想要進行序列化的集合對象做爲參數,Json.Net會序列化集合以及全部它包含的值。
示例:
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime ExpiryDate { get; set; }
}
測試:
Product p1 = new Product()
{
Name = "Product 1",
Price = 99.95m,
ExpiryDate = new DateTime(2010, 12, 19, 0, 0, 0, DateTimeKind.Utc)
};
Product p2 = new Product
{
Name = "Product 2",
Price = 12.50m,
ExpiryDate = new DateTime(2011, 1, 1, 0, 0, 0, DateTimeKind.Utc)
};
List<Product> products = new List<Product>();
products.Add(p1);
products.Add(p2);
string json = JsonConvert.SerializeObject(products, Formatting.Indented);
Console.WriteLine(json);
輸出結果:
[
{
"Name": "Product 1",
"Price": 99.95,
"ExpiryDate": "2010-12-19T00:00:00Z"
},
{
"Name": "Product 2",
"Price": 12.50,
"ExpiryDate": "2011-01-01T00:00:00Z"
}
]
->Deserializing
爲了反序列化Json到一個.Net集合中,只要指定一個您想要反序列化的集合類型就能夠了,Json.Net支持多種類型的集合.
示例:
string json2 = @"[
{
""Name"": ""Product 1"",
""ExpiryDate"": ""2010-12-19T00:00:00Z"",
""Price"": 99.95,
""Sizes"": null
},
{
""Name"": ""Product 2"",
""ExpiryDate"": ""2011-01-01T00:00:00Z"",
""Price"": 12.50,
""Sizes"": null
}
]";
List<Product> productList = JsonConvert.DeserializeObject<List<Product>>(json2);
Console.WriteLine(productList.Count);//2
Product product1 = productList[0];
Console.WriteLine(product1.Name);//Product 1
->Deserializing Dictionaries
使用Json.Net你也能夠反序列化一個Json對象到一個.Net的泛型Dictionary中.Json對象的屬性名和屬性值將會被添加到Dictionary中.
示例:
string jsonDictionary = @"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonDictionary);
Console.WriteLine(dic.Count);//2
Console.WriteLine(dic["key1"]);//value1
Json.Net支持序列化回調方法,回調方法經過Json序列化器(JsonSerializer)能夠用來操做一個對象,在它被序列化和反序列化以前或者以後.
爲了告訴序列化器在對象的序列化生命週期中哪一個方法應該被調用,須要用適當的attribute(OnSerializingAttribute, OnSerializedAttribute, OnDeserializingAttribute, OnDeserializedAttribute)來標記方法.
例如對象序列化的回調方法:
using Newtonsoft.Json;
using System.Runtime.Serialization;
public class SerializationEventTestObject
{
// This member is serialized and deserialized with no change.
public int Member1 { get; set; }
// The value of this field is set and reset during and
// after serialization.
public string Member2 { get; set; }
// This field is not serialized. The OnDeserializedAttribute
// is used to set the member value after serialization.
[JsonIgnore]
public string Member3 { get; set; }
// This field is set to null, but populated after deserialization.
public string Member4 { get; set; }
public SerializationEventTestObject()
{
Member1 = 11;
Member2 = "Hello World!";
Member3 = "This is a nonserialized value";
Member4 = null;
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
Member2 = "This value went into the data file during serialization.";
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
Member2 = "This value was reset after serialization.";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Member3 = "This value was set during deserialization";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Member4 = "This value was set after deserialization.";
}
}
示例對象被序列化和反序列化:
SerializationEventTestObject obj = new SerializationEventTestObject();
Console.WriteLine(obj.Member1);// 11
Console.WriteLine(obj.Member2);// Hello World!
Console.WriteLine(obj.Member3);// This is a nonserialized value
Console.WriteLine(obj.Member4);// null
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Console.WriteLine(json);
Console.WriteLine(obj.Member1);//11
Console.WriteLine(obj.Member2);// This value was reset after serialization.
Console.WriteLine(obj.Member3);// This is a nonserialized value
Console.WriteLine(obj.Member4);// null
obj = JsonConvert.DeserializeObject<SerializationEventTestObject>(json);
Console.WriteLine(obj.Member1);//11
Console.WriteLine(obj.Member2);// This value went into the data file during serialization.
Console.WriteLine(obj.Member3);// This value was set during deserialization
Console.WriteLine(obj.Member4);// This value was set after deserialization.
Attributes 能夠用來控制Json.Net如何序列化和反序列化.Net對象。
>JsonObjectAttribute--標記在類上,用於控制該類如何被序列化爲一個Json對象(JSON Object)
>JsonArrayAttribute--標記在集合上,用於控制該集合如何被序列化爲一個Json集合(JSON Array)
>JsonPropertyAttribute--標記在字段和屬性上,用於控制它如何被序列化爲一個Json對象中的屬性
>JsonConverterAttribute--標記在類或者字段和屬性上,用於序列化時指定Json轉換器(JsonConverter)
和使用內置的Json.Net attributes同樣,當肯定Json如何被序列化和反序列化時,Json.Net也查找DataContract和DataMember attributes。若是都存在,Json.Net 序列化特性將優先使用。
示例:
DateTime類型在Json中表示是很難的。
問題來源於JSON spec (Json規範)自身,沒有精確的語法。這個規範包括objects, arrays, strings, integers 和 floats,可是對於date是什麼樣子的沒有定義準確的標準。
關於時間,Json.Net使用的默認格式與微軟:"\/Date(1198908717056)\/"相同,您能夠今後外得到更多信息.
DateTime JsonConverters
因爲在Json中沒有關於時間的準確標準,當與其餘系統進行互操做時就會有大量不一樣的時間格式。幸運的是,Json.Net爲了處理讀寫自定義時間提供了一個解決方案:JsonConverters. JsonConverter是用來重寫一個類型如何被序列化的。
示例:
public class LogEntry
{
public string Details { get; set; }
public DateTime LogDate { get; set; }
}
測試1:
LogEntry logEntry = new LogEntry()
{
LogDate = new DateTime(2010, 12, 19, 0, 0, 0, DateTimeKind.Utc),
Details = "Application started."
};
string defaultJson = JsonConvert.SerializeObject(logEntry, Formatting.Indented);
Console.WriteLine(defaultJson);
輸出結果:
{
"Details": "Application started.",
"LogDate": "\/Date(1292716800000)\/"
}
測試2:
string javascriptJson = JsonConvert.SerializeObject(logEntry, Formatting.Indented, new JavaScriptDateTimeConverter());
Console.WriteLine(javascriptJson);
輸出結果:
{
"Details": "Application started.",
"LogDate": new Date(
1292716800000
)
}
測試3:
string isoJson = JsonConvert.SerializeObject(logEntry, Formatting.Indented, new IsoDateTimeConverter());
Console.WriteLine(isoJson);
輸出結果:
{
"Details": "Application started.",
"LogDate": "2010-12-19T00:00:00Z"
}
簡單地,經過JsonConverter您可使用Json.Net的序列化器
>JavaScriptDateTimeConverter
JavaScriptDateTimeConverter類是來自於Json.Net的兩個DataTime Json轉換器之一,這個轉換器序列化一個DateTime類型爲一個JavaScipt日期對象(https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Date)
new Date(1292716800000)
從技術上講,根據規範這是無效的數據格式,可是全部的瀏覽器、和一些Json的框架包括Json.Net都支持它。
>IsoDateTimeConverter
IsoDateTimeConverter序列一個DateTime類型爲一個ISO 8601格式的字符串.
"2010-12-19T00:00:00Z"
IsoDateTimeConverter 類有一個屬性DateTimeFormat,用來更進一步的自定義字符串格式.
最後要注意的一件事是,全部被Json.Net返回的日期值都是UTC Time
Json.Net 支持 Json 與Xml之間的相互轉換.
轉換規則:
1.元素保持不變
2.屬性添加前綴@
3.單個子文本結點直接做爲元素結點的值,不然經過#text訪問
4.XML聲明和處理指令以?爲前綴
5.字符數據(Character data)、註釋、whitespace 和significate whitespace結點分別經過#cdata-section,#comment,#whitespace and #significate-whitespace 訪問。
6.同一級多個相同名字的結點做爲一組,放到同一個集合中
7.空元素爲null
using Newtonsoft.Json;
測試:
string xml = <?xml version=""1.0"" standalone=""no""?>
<root>
<person id=""1"">
<name>Alan</name>
<url>http://www.google.com</url>
</person>
<person id=""2"">
<name>Louis</name>
<url>http://www.yahoo.com</url>
</person>
Hello World
</root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
//XML to JSON
string jsonText = JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.Indented);
Console.WriteLine(jsonText);
輸出結果:
{
"?xml": {
"@version": "1.0",
"@standalone": "no"
},
"root": {
"person": [
{
"@id": "1",
"name": "Alan",
"url": "http://www.google.com"
},
{
"@id": "2",
"name": "Louis",
"url": "http://www.yahoo.com"
}
],
"#text": "\r\n Hello World\r\n "
}
}
//JSON to XML
XmlDocument docJson = (XmlDocument)JsonConvert.DeserializeXmlNode(jsonText);
Console.WriteLine(docJson.InnerXml);
爲了手動讀寫Json對象,Json.Net提供了JsonReader 和 JsonWriter這兩個抽象類及其相應的派生類:
1.JsonTextReader 和 JsonTextWriter
用來讀寫Json對象的文本,JsonTextWriter 有大量設置去控制Json對象的格式。
測試:
//寫操做
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (JsonWriter jsonWriter = new JsonTextWriter(sw))
{
jsonWriter.Formatting = Formatting.Indented;
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("CPU");
jsonWriter.WriteValue("Intel");
jsonWriter.WritePropertyName("PSU");
jsonWriter.WriteValue("500W");
jsonWriter.WritePropertyName("Drives");
jsonWriter.WriteStartArray();
jsonWriter.WriteValue("DVD read/writer");
jsonWriter.WriteComment("(broken)");
jsonWriter.WriteValue("500 gigabyte hard drive");
jsonWriter.WriteValue("200 gigabype hard drive");
jsonWriter.WriteEndArray();
jsonWriter.WriteEndObject();
}
Console.WriteLine(sb.ToString());
輸出結果:
{
"CPU": "Intel",
"PSU": "500W",
"Drives": [
"DVD read/writer"
/*(broken)*/,
"500 gigabyte hard drive",
"200 gigabype hard drive"
]
}
//讀操做
TextReader txtReader = new StringReader(sb.ToString());
using (JsonReader jsonReader = new JsonTextReader(txtReader))
{
string readResult = "{\n";
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.PropertyName)
{
readResult += (string)jsonReader.Value + ":";
}
else if (jsonReader.TokenType == JsonToken.String)
{
readResult += (string)jsonReader.Value + "\n";
}
else if (jsonReader.TokenType == JsonToken.StartArray)
{
readResult += "[\n";
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.EndArray)
{
readResult = readResult.Remove(readResult.Length - 2, 1);
readResult += "]\n";
break;
}
if (jsonReader.TokenType == JsonToken.String)
readResult += (string)jsonReader.Value + ",\n";
else if (jsonReader.TokenType == JsonToken.Comment)
readResult += "/*" + (string)jsonReader.Value + "*/,\n";
}
}
}
readResult += "}\n";
Console.WriteLine(readResult);
}
2.JTokenReader and JTokenWriter
JTokenReader and JTokenWriter是讀寫Linq to Json對象的,他們存在於Newtonsoft.Json.Linq名字空間中
JObject o = new JObject(
new JProperty("Name", "ZhangSan"),
new JProperty("BirthDay", new DateTime(1985, 11, 27)));
JsonSerializer serializer = new JsonSerializer();
Person person = (Person)serializer.Deserialize(new JTokenReader(o), typeof(Person));
Console.WriteLine(person.Name);//輸出ZhangSan
using Newtonsoft.Json.Linq;
定義類:
public class Product
{
public string Name { get; set; }
public DateTime Expiry { get; set; }
public decimal Price { get; set; }
public string[] Sizes { get; set; }
}
測試:
Product product = new Product
{
Name = "Apple",
Expiry = new DateTime(2010, 12, 18),
Price = 3.99M,
Sizes = new string[] { "Small", "Medium", "Large" }
};
string serializedJson = JsonConvert.SerializeObject(product);
JObject o = JObject.Parse(serializedJson);
string name = (string)o["Name"];
//Apple
JArray sizes = (JArray)o["Sizes"];
string smallest = (string)sizes[0];
Response.Write(name + "," + smallest + "<br/>");//輸出Small
//SelectToken
smallest = (string)o.SelectToken("Sizes[0]");
Response.Write(smallest + "<br/>");//輸出Small
//SelectToken with Linq
var sizeLen5 = o["Sizes"].Select(i => (string)i).Where(i => i.Length == 5).ToList<string>();
foreach (var size in sizeLen5)
{
Response.Write((string)size+ " <br/>");
};//輸出Small和Large
注:JArray表示一個Json集合,JObject表示一個Json對象。
使用Newtonsoft.Json這是一個開源的Json.Net庫。
下載地址:http://json.codeplex.com/releases/view/50552。當前版本爲 Release 8
從下載到的源代碼中獲取Newtonsoft.Json.Net20.dll,添加到本身的工程中。
using Newtonsoft.Json;
定義類:
public class Message
{
public string Address { get; set; }
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public object Body { get; set; }
}
public class SearchDetails
{
public string Query { get; set; }
public string Language { get; set; }
}
測試:
Message message = new Message
{
Address = "http://google.com",
Body = new SearchDetails { Query = "Json.Net", Language = "en-us" }
};
string jsonMsg = JsonConvert.SerializeObject(message, Formatting.Indented);//Indented表示以縮進形式顯示結果
System.Diagnostics.Debug.Write(jsonMsg);
Message deserialized = JsonConvert.DeserializeObject<Message>(jsonMsg);
SearchDetails searchDetails = (SearchDetails)deserialized.Body;
Response.Write(searchDetails.Query + "," + searchDetails.Language + "<br/>");
Debug輸出結果格式:
{
"Address": "http://google.com",
"Body": {
"$type": "TestJsonSerialization.SearchDetails, TestJsonSerialization",
"Query": "Json.Net",
"Language": "en-us"
}
}
注:1.JsonProperty標記字段或屬性,用來控制它做爲一個Json對象的屬性序列化。
2.TypeNameHandling 用來爲Json序列化指定類型名。它有幾個枚舉值:
Member | Description |
---|---|
None | Do not include the .NET type name when serializing types. |
Objects | Include the .NET type name when serializing into a JSON object structure. |
Arrays | Include the .NET type name when serializing into a JSON array structure. |
Auto | Include the .NET type name when the type of the object being serialized is not the same as its declared type. |
All | Always include the .NET type name when serializing. |