-Added missing XML documentation

-Fixed potential null reference error when getting attributes
-Performance documentation
This commit is contained in:
James Newton-King
2012-10-27 19:25:04 +13:00
parent 0e4611ed86
commit 1fa5e4a22e
14 changed files with 459 additions and 13 deletions
+84
View File
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<topic id="Performance" revisionNumber="1">
<developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
<introduction>
<para>Out of the box Json.NET is faster than DataContractJsonSerializer and JavaScriptSerializer.
Here are some tips to make it go even faster.</para>
</introduction>
<section>
<title>Optimize Memory Usage</title>
<content>
<para>To keep an application consistantly fast it is important to minimize the
amount of time the .NET framework spends performing <externalLink>
<linkText>garbage collection</linkText>
<linkUri>http://msdn.microsoft.com/en-us/library/ms973837.aspx</linkUri>
<linkTarget>_blank</linkTarget>
</externalLink>.
Allocating too many objects, or allocating very large objects can slow down or even
halt an application while garbage collection is in progress.
</para>
<para>To minimize memory usage and the number of objects allocated Json.NET supports
serializing and deserializing directly to a stream. Reading or writing JSON a piece at a time instead of having
the entire JSON string loaded into memory is especially important when working with JSON
documents greater than 85kb in size to avoid the JSON string ending up in the <externalLink>
<linkText>large object heap</linkText>
<linkUri>http://msdn.microsoft.com/en-us/magazine/cc534993.aspx</linkUri>
<linkTarget>_blank</linkTarget>
</externalLink>.</para>
<code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\PerformanceTests.cs" region="DeserializeString" title="Deserialize String" />
<code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\PerformanceTests.cs" region="DeserializeStream" title="Deserialize Stream" />
</content>
</section>
<section>
<title>JsonConverters</title>
<content>
<para>Passing a <codeEntityReference>T:Newtonsoft.Json.JsonConverter</codeEntityReference> to SerializeObject or DeserializeObject provides a simple way to completely
change how an object is serialized. There is however a small overhead; the CanConvert method is called for every
type to check whether serialization should be handled by that JsonConverter.</para>
<para>There are a couple of ways to continue to use JsonConverters without any overhead. The simplest way
is to specify the JsonConverter using the <codeEntityReference>T:Newtonsoft.Json.JsonConverterAttribute</codeEntityReference>. This attribute tells the serializer
to always use that converter when serializing and deserializing the type, without the check.</para>
<code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\PerformanceTests.cs" region="JsonConverterAttribute" title="Use JsonConverter with JsonConverterAttribute" />
<para>If the class you want to convert isn't your own and you're unable to use an attribute a JsonConverter can still be used by
creating your own <codeEntityReference>T:Newtonsoft.Json.Serialization.IContractResolver</codeEntityReference>.</para>
<code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\PerformanceTests.cs" region="JsonConverterContractResolver" title="Use JsonConverter with IContractResolver" />
<para>The IContractResolver in the example above will set all DateTimes to use the JavaScriptDateConverter.</para>
</content>
</section>
<section>
<title>Manually Serialize</title>
<content>
<para>The absolute fastest way to read and write JSON is to use JsonTextReader and JsonTextWriter directly. Using a reader or writer
directly skips any of the overhead from a serializer such as reflection.</para>
<code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\PerformanceTests.cs" region="ReaderWriter" title="Manually serialize using JsonTextWriter" />
<para>If performance is important and you don't mind more code to get it then this is your best choice.</para>
</content>
</section>
<section>
<title>Benchmarks</title>
<content>
<mediaLink>
<image class="image" xlink:href="performance" mimeType="image/png" width="643" height="345" />
<summary>Json.NET Performance</summary>
</mediaLink>
</content>
</section>
<relatedTopics>
<codeEntityReference>T:Newtonsoft.Json.JsonSerializer</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonConverter</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonConverterAttribute</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonTextWriter</codeEntityReference>
<codeEntityReference>T:Newtonsoft.Json.JsonTextReader</codeEntityReference>
</relatedTopics>
</developerConceptualDocument>
</topic>
+2 -1
View File
@@ -21,7 +21,8 @@
<Topic id="QueryingLINQtoJSON" visible="True" title="Querying JSON with LINQ" /> <Topic id="QueryingLINQtoJSON" visible="True" title="Querying JSON with LINQ" />
<Topic id="SelectToken" visible="True" title="Querying JSON with SelectToken" /> <Topic id="SelectToken" visible="True" title="Querying JSON with SelectToken" />
</Topic> </Topic>
<Topic id="JsonSchema" visible="True" isSelected="true" title="Validating JSON" /> <Topic id="Performance" visible="True" isSelected="true" title="Performance" />
<Topic id="JsonSchema" visible="True" title="Validating JSON" />
<Topic id="ReadingWritingJSON" visible="True" title="Basic Reading and Writing JSON" /> <Topic id="ReadingWritingJSON" visible="True" title="Basic Reading and Writing JSON" />
<Topic id="ConvertingJSONandXML" visible="True" title="Converting between JSON and XML" /> <Topic id="ConvertingJSONandXML" visible="True" title="Converting between JSON and XML" />
</Topics> </Topics>
+5
View File
@@ -141,6 +141,7 @@
<None Include="ContractResolver.aml" /> <None Include="ContractResolver.aml" />
<None Include="ConvertingJSONandXML.aml" /> <None Include="ConvertingJSONandXML.aml" />
<None Include="CreatingLINQtoJSON.aml" /> <None Include="CreatingLINQtoJSON.aml" />
<None Include="Performance.aml" />
<None Include="JsonSchema.aml" /> <None Include="JsonSchema.aml" />
<None Include="JsonSchema.aml" /> <None Include="JsonSchema.aml" />
<None Include="ParsingLINQtoJSON.aml" /> <None Include="ParsingLINQtoJSON.aml" />
@@ -165,6 +166,10 @@
<ContentLayout Include="doc.content" /> <ContentLayout Include="doc.content" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Image Include="performance.png">
<ImageId>performance</ImageId>
<AlternateText>performance</AlternateText>
</Image>
<Image Include="logo.jpg"> <Image Include="logo.jpg">
<ImageId>logo</ImageId> <ImageId>logo</ImageId>
<AlternateText>logo</AlternateText> <AlternateText>logo</AlternateText>
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

@@ -0,0 +1,218 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
#if !(NET35 || NET20 || PORTABLE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
#if !NETFX_CORE
using NUnit.Framework;
#else
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
#endif
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Tests.TestObjects;
using Newtonsoft.Json.Utilities;
using System.Globalization;
namespace Newtonsoft.Json.Tests.Documentation
{
public class HttpClient
{
public Task<string> GetStringAsync(string requestUri)
{
return null;
}
public Task<Stream> GetStreamAsync(string requestUri)
{
return null;
}
}
#region JsonConverterAttribute
[JsonConverter(typeof(PersonConverter))]
public class Person
{
public Person()
{
Likes = new List<string>();
}
public string Name { get; set; }
public IList<string> Likes { get; private set; }
}
#endregion
#region JsonConverterContractResolver
public class ConverterContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
JsonContract contract = base.CreateContract(objectType);
if (objectType == typeof(DateTime) || objectType == typeof(DateTimeOffset))
contract.Converter = new JavaScriptDateTimeConverter();
return contract;
}
}
#endregion
public class PersonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return null;
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Person));
}
}
[TestFixture]
public class PerformanceTests : TestFixtureBase
{
[Test]
public void ConverterContractResolverTest()
{
string json = JsonConvert.SerializeObject(new DateTime(2000, 10, 10, 10, 10, 10, DateTimeKind.Utc), new JsonSerializerSettings
{
ContractResolver = new ConverterContractResolver()
});
Console.WriteLine(json);
}
public void DeserializeString()
{
#region DeserializeString
HttpClient client = new HttpClient();
// read the json into a string
// string could potentially be very large and cause memory problems
string json = client.GetStringAsync("http://www.test.com/large.json").Result;
Person p = JsonConvert.DeserializeObject<Person>(json);
#endregion
}
public void DeserializeStream()
{
#region DeserializeStream
HttpClient client = new HttpClient();
using (Stream s = client.GetStreamAsync("http://www.test.com/large.json").Result)
using (StreamReader sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
JsonSerializer serializer = new JsonSerializer();
// read the json from a stream
// json size doesn't matter because only a small piece is read at a time from the HTTP request
Person p = serializer.Deserialize<Person>(reader);
}
#endregion
}
}
public static class PersonWriter
{
#region ReaderWriter
public static string ToJson(this Person p)
{
StringWriter sw = new StringWriter();
JsonTextWriter writer = new JsonTextWriter(sw);
// {
writer.WriteStartObject();
// "name" : "Jerry"
writer.WritePropertyName("name");
writer.WriteValue(p.Name);
// "likes": ["Comedy", "Superman"]
writer.WritePropertyName("likes");
writer.WriteStartArray();
foreach (string like in p.Likes)
{
writer.WriteValue(like);
}
writer.WriteEndArray();
// }
writer.WriteEndObject();
return sw.ToString();
}
#endregion
public static Person ToPerson(this string s)
{
StringReader sr = new StringReader(s);
JsonTextReader reader = new JsonTextReader(sr);
Person p = new Person();
// {
reader.Read();
// "name"
reader.Read();
// "Jerry"
p.Name = reader.ReadAsString();
// "likes"
reader.Read();
// [
reader.Read();
// "Comedy", "Superman", ]
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
{
p.Likes.Add((string)reader.Value);
}
// }
reader.Read();
return p;
}
}
}
#endif
@@ -1881,6 +1881,24 @@ Parameter name: arrayIndex",
Assert.IsTrue(JToken.DeepEquals(b, a)); Assert.IsTrue(JToken.DeepEquals(b, a));
} }
[Test]
public void GetValueBlogExample()
{
JObject o = JObject.Parse(@"{
'name': 'Lower',
'NAME': 'Upper'
}");
string exactMatch = (string)o.GetValue("NAME", StringComparison.OrdinalIgnoreCase);
// Upper
string ignoreCase = (string)o.GetValue("Name", StringComparison.OrdinalIgnoreCase);
// Lower
Assert.AreEqual("Upper", exactMatch);
Assert.AreEqual("Lower", ignoreCase);
}
[Test] [Test]
public void GetValue() public void GetValue()
{ {
@@ -117,6 +117,7 @@
<Compile Include="Converters\StringEnumConverterTests.cs" /> <Compile Include="Converters\StringEnumConverterTests.cs" />
<Compile Include="Converters\VersionConverterTests.cs" /> <Compile Include="Converters\VersionConverterTests.cs" />
<Compile Include="Documentation\ConvertingJsonAndXmlTests.cs" /> <Compile Include="Documentation\ConvertingJsonAndXmlTests.cs" />
<Compile Include="Documentation\PerformanceTests.cs" />
<Compile Include="Documentation\JsonSchemaTests.cs" /> <Compile Include="Documentation\JsonSchemaTests.cs" />
<Compile Include="Documentation\ReadingAndWritingJsonTests.cs" /> <Compile Include="Documentation\ReadingAndWritingJsonTests.cs" />
<Compile Include="Documentation\LinqToJsonTests.cs" /> <Compile Include="Documentation\LinqToJsonTests.cs" />
+95 -6
View File
@@ -33,7 +33,6 @@ using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Web.Script.Serialization; using System.Web.Script.Serialization;
using System.Xml.Linq; using System.Xml.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Utilities;
using NUnit.Framework; using NUnit.Framework;
using System.Runtime.Serialization.Json; using System.Runtime.Serialization.Json;
@@ -123,6 +122,8 @@ namespace Newtonsoft.Json.Tests
TestClass test = CreateSerializationObject(); TestClass test = CreateSerializationObject();
SerializeTests(test); SerializeTests(test);
Deserialize();
} }
private void SerializeTests(object value) private void SerializeTests(object value)
@@ -153,6 +154,7 @@ namespace Newtonsoft.Json.Tests
BenchmarkDeserializeMethod<T>(SerializeMethod.JavaScriptSerializer, json); BenchmarkDeserializeMethod<T>(SerializeMethod.JavaScriptSerializer, json);
BenchmarkDeserializeMethod<T>(SerializeMethod.DataContractJsonSerializer, json); BenchmarkDeserializeMethod<T>(SerializeMethod.DataContractJsonSerializer, json);
BenchmarkDeserializeMethod<T>(SerializeMethod.JsonNet, json); BenchmarkDeserializeMethod<T>(SerializeMethod.JsonNet, json);
BenchmarkDeserializeMethod<T>(SerializeMethod.JsonNetManual, json);
} }
[Test] [Test]
@@ -658,12 +660,94 @@ namespace Newtonsoft.Json.Tests
var value = (T) serializer.Deserialize(new StringReader(json), type); var value = (T) serializer.Deserialize(new StringReader(json), type);
return value; return value;
//JsonTextReader reader = new JsonTextReader(new StringReader(JsonText)); }
//while (reader.Read())
//{
//} public TestClass DeserializeJsonNetManual(string json)
//return default(T); {
TestClass c = new TestClass();
JsonTextReader reader = new JsonTextReader(new StringReader(json));
reader.Read();
while (reader.Read())
{
if (reader.TokenType == JsonToken.PropertyName)
{
string propertyName = (string) reader.Value;
switch (propertyName)
{
case "strings":
reader.Read();
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
{
c.strings.Add((string) reader.Value);
}
break;
case "dictionary":
reader.Read();
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
{
string key = (string) reader.Value;
c.dictionary.Add(key, reader.ReadAsInt32().GetValueOrDefault());
}
break;
case "Name":
c.Name = reader.ReadAsString();
break;
case "Now":
c.Now = reader.ReadAsDateTime().GetValueOrDefault();
break;
case "BigNumber":
c.BigNumber = reader.ReadAsDecimal().GetValueOrDefault();
break;
case "Address1":
reader.Read();
c.Address1 = CreateAddress(reader);
break;
case "Addresses":
reader.Read();
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
{
var address = CreateAddress(reader);
c.Addresses.Add(address);
}
break;
}
}
else
{
break;
}
}
return c;
}
private static Address CreateAddress(JsonTextReader reader)
{
Address a = new Address();
while (reader.Read())
{
if (reader.TokenType == JsonToken.PropertyName)
{
switch ((string) reader.Value)
{
case "Street":
a.Street = reader.ReadAsString();
break;
case "Phone":
a.Phone = reader.ReadAsString();
break;
case "Entered":
a.Entered = reader.ReadAsDateTime().GetValueOrDefault();
break;
}
}
else
{
break;
}
}
return a;
} }
public T DeserializeJsonNetBinary<T>(byte[] bson) public T DeserializeJsonNetBinary<T>(byte[] bson)
@@ -703,6 +787,11 @@ namespace Newtonsoft.Json.Tests
return DeserializeJsonNet<T>((string)json, false); return DeserializeJsonNet<T>((string)json, false);
case SerializeMethod.JsonNetWithIsoConverter: case SerializeMethod.JsonNetWithIsoConverter:
return DeserializeJsonNet<T>((string)json, true); return DeserializeJsonNet<T>((string)json, true);
case SerializeMethod.JsonNetManual:
if (typeof(T) == typeof(TestClass))
return (T)(object)DeserializeJsonNetManual((string)json);
return default(T);
case SerializeMethod.JsonNetBinary: case SerializeMethod.JsonNetBinary:
return DeserializeJsonNetBinary<T>((byte[]) json); return DeserializeJsonNetBinary<T>((byte[]) json);
case SerializeMethod.BinaryFormatter: case SerializeMethod.BinaryFormatter:
@@ -76,5 +76,5 @@ using System.Security;
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")] [assembly: AssemblyVersion("4.5.0.0")]
#if !PocketPC #if !PocketPC
[assembly: AssemblyFileVersion("4.5.9.15402")] [assembly: AssemblyFileVersion("4.5.10.15427")]
#endif #endif
@@ -46,6 +46,33 @@ namespace Newtonsoft.Json.Tests.Serialization
[TestFixture] [TestFixture]
public class DefaultValueHandlingTests : TestFixtureBase public class DefaultValueHandlingTests : TestFixtureBase
{ {
[Test]
public void Include()
{
Invoice invoice = new Invoice
{
Company = "Acme Ltd.",
Amount = 50.0m,
Paid = false,
FollowUpDays = 30,
FollowUpEmailAddress = string.Empty,
PaidDate = null
};
string included = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Include });
Assert.AreEqual(@"{
""Company"": ""Acme Ltd."",
""Amount"": 50.0,
""Paid"": false,
""PaidDate"": null,
""FollowUpDays"": 30,
""FollowUpEmailAddress"": """"
}", included);
}
[Test] [Test]
public void SerializeInvoice() public void SerializeInvoice()
{ {
+3
View File
@@ -381,6 +381,7 @@ namespace Newtonsoft.Json.Linq
/// <summary> /// <summary>
/// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name. /// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
/// </summary> /// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <value>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</value> /// <value>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</value>
public JToken GetValue(string propertyName) public JToken GetValue(string propertyName)
{ {
@@ -392,6 +393,8 @@ namespace Newtonsoft.Json.Linq
/// The exact property name will be searched for first and if no matching property is found then /// The exact property name will be searched for first and if no matching property is found then
/// the <see cref="StringComparison"/> will be used to match a property. /// the <see cref="StringComparison"/> will be used to match a property.
/// </summary> /// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
/// <value>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</value> /// <value>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</value>
public JToken GetValue(string propertyName, StringComparison comparison) public JToken GetValue(string propertyName, StringComparison comparison)
{ {
@@ -90,7 +90,7 @@ using System.Security;
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")] [assembly: AssemblyVersion("4.5.0.0")]
#if !PocketPC #if !PocketPC
[assembly: AssemblyFileVersion("4.5.9.15402")] [assembly: AssemblyFileVersion("4.5.10.15427")]
#endif #endif
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]
@@ -709,7 +709,7 @@ namespace Newtonsoft.Json.Utilities
{ {
T[] attributes = GetAttributes<T>(attributeProvider, inherit); T[] attributes = GetAttributes<T>(attributeProvider, inherit);
return attributes.SingleOrDefault(); return (attributes != null) ? attributes.SingleOrDefault() : null;
} }
#if !(NETFX_CORE) #if !(NETFX_CORE)
@@ -28,6 +28,7 @@ using System.Collections.Generic;
#if NET20 #if NET20
using Newtonsoft.Json.Utilities.LinqBridge; using Newtonsoft.Json.Utilities.LinqBridge;
#endif #endif
using System.Threading;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities namespace Newtonsoft.Json.Utilities
@@ -44,13 +45,11 @@ namespace Newtonsoft.Json.Utilities
throw new ArgumentNullException("creator"); throw new ArgumentNullException("creator");
_creator = creator; _creator = creator;
_store = new Dictionary<TKey, TValue>();
} }
public TValue Get(TKey key) public TValue Get(TKey key)
{ {
if (_store == null)
return AddValue(key);
TValue value; TValue value;
if (!_store.TryGetValue(key, out value)) if (!_store.TryGetValue(key, out value))
return AddValue(key); return AddValue(key);
@@ -79,6 +78,7 @@ namespace Newtonsoft.Json.Utilities
Dictionary<TKey, TValue> newStore = new Dictionary<TKey, TValue>(_store); Dictionary<TKey, TValue> newStore = new Dictionary<TKey, TValue>(_store);
newStore[key] = value; newStore[key] = value;
Thread.MemoryBarrier();
_store = newStore; _store = newStore;
} }