diff --git a/Doc/Performance.aml b/Doc/Performance.aml
new file mode 100644
index 00000000..ce89d2ff
--- /dev/null
+++ b/Doc/Performance.aml
@@ -0,0 +1,84 @@
+
+
+
+
+ Out of the box Json.NET is faster than DataContractJsonSerializer and JavaScriptSerializer.
+ Here are some tips to make it go even faster.
+
+
+ Optimize Memory Usage
+
+ To keep an application consistantly fast it is important to minimize the
+ amount of time the .NET framework spends performing
+garbage collection
+http://msdn.microsoft.com/en-us/library/ms973837.aspx
+_blank
+.
+ Allocating too many objects, or allocating very large objects can slow down or even
+ halt an application while garbage collection is in progress.
+
+ 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
+large object heap
+http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
+_blank
+.
+
+
+
+
+
+
+
+ JsonConverters
+
+ Passing a T:Newtonsoft.Json.JsonConverter 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.
+ There are a couple of ways to continue to use JsonConverters without any overhead. The simplest way
+ is to specify the JsonConverter using the T:Newtonsoft.Json.JsonConverterAttribute. This attribute tells the serializer
+ to always use that converter when serializing and deserializing the type, without the check.
+
+
+
+ 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 T:Newtonsoft.Json.Serialization.IContractResolver.
+
+
+
+ The IContractResolver in the example above will set all DateTimes to use the JavaScriptDateConverter.
+
+
+
+ Manually Serialize
+
+ 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.
+
+
+
+ If performance is important and you don't mind more code to get it then this is your best choice.
+
+
+
+ Benchmarks
+
+
+
+
+ Json.NET Performance
+
+
+
+
+
+ T:Newtonsoft.Json.JsonSerializer
+ T:Newtonsoft.Json.JsonConverter
+ T:Newtonsoft.Json.JsonConverterAttribute
+ T:Newtonsoft.Json.JsonTextWriter
+ T:Newtonsoft.Json.JsonTextReader
+
+
+
\ No newline at end of file
diff --git a/Doc/doc.content b/Doc/doc.content
index a7d32cd5..47ec2e05 100644
--- a/Doc/doc.content
+++ b/Doc/doc.content
@@ -21,7 +21,8 @@
-
+
+
\ No newline at end of file
diff --git a/Doc/doc.shfbproj b/Doc/doc.shfbproj
index af9f3ede..581fb1a9 100644
--- a/Doc/doc.shfbproj
+++ b/Doc/doc.shfbproj
@@ -141,6 +141,7 @@
+
@@ -165,6 +166,10 @@
+
+ performance
+ performance
+
logo
logo
diff --git a/Doc/performance.png b/Doc/performance.png
new file mode 100644
index 00000000..cd63d1bd
Binary files /dev/null and b/Doc/performance.png differ
diff --git a/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs
new file mode 100644
index 00000000..b0058366
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs
@@ -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 GetStringAsync(string requestUri)
+ {
+ return null;
+ }
+
+ public Task GetStreamAsync(string requestUri)
+ {
+ return null;
+ }
+ }
+
+ #region JsonConverterAttribute
+ [JsonConverter(typeof(PersonConverter))]
+ public class Person
+ {
+ public Person()
+ {
+ Likes = new List();
+ }
+
+ public string Name { get; set; }
+ public IList 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(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(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
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs
index 704faf76..12983fc7 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs
@@ -1881,6 +1881,24 @@ Parameter name: arrayIndex",
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]
public void GetValue()
{
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 6885929d..afa8eb6d 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -117,6 +117,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
index 9db01802..7bcc6a18 100644
--- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
+++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
@@ -33,7 +33,6 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Web.Script.Serialization;
using System.Xml.Linq;
-using System.Xml.Serialization;
using Newtonsoft.Json.Utilities;
using NUnit.Framework;
using System.Runtime.Serialization.Json;
@@ -123,6 +122,8 @@ namespace Newtonsoft.Json.Tests
TestClass test = CreateSerializationObject();
SerializeTests(test);
+
+ Deserialize();
}
private void SerializeTests(object value)
@@ -153,6 +154,7 @@ namespace Newtonsoft.Json.Tests
BenchmarkDeserializeMethod(SerializeMethod.JavaScriptSerializer, json);
BenchmarkDeserializeMethod(SerializeMethod.DataContractJsonSerializer, json);
BenchmarkDeserializeMethod(SerializeMethod.JsonNet, json);
+ BenchmarkDeserializeMethod(SerializeMethod.JsonNetManual, json);
}
[Test]
@@ -658,12 +660,94 @@ namespace Newtonsoft.Json.Tests
var value = (T) serializer.Deserialize(new StringReader(json), type);
return value;
- //JsonTextReader reader = new JsonTextReader(new StringReader(JsonText));
- //while (reader.Read())
- //{
+ }
- //}
- //return default(T);
+ public TestClass DeserializeJsonNetManual(string json)
+ {
+ 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(byte[] bson)
@@ -703,6 +787,11 @@ namespace Newtonsoft.Json.Tests
return DeserializeJsonNet((string)json, false);
case SerializeMethod.JsonNetWithIsoConverter:
return DeserializeJsonNet((string)json, true);
+ case SerializeMethod.JsonNetManual:
+ if (typeof(T) == typeof(TestClass))
+ return (T)(object)DeserializeJsonNetManual((string)json);
+
+ return default(T);
case SerializeMethod.JsonNetBinary:
return DeserializeJsonNetBinary((byte[]) json);
case SerializeMethod.BinaryFormatter:
diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
index 72ebb846..19683bd3 100644
--- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
@@ -76,5 +76,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
#if !PocketPC
-[assembly: AssemblyFileVersion("4.5.9.15402")]
+[assembly: AssemblyFileVersion("4.5.10.15427")]
#endif
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs
index b2455d0a..cb530ffa 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/DefaultValueHandlingTests.cs
@@ -46,6 +46,33 @@ namespace Newtonsoft.Json.Tests.Serialization
[TestFixture]
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]
public void SerializeInvoice()
{
diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs
index 531f824b..2f8d1d43 100644
--- a/Src/Newtonsoft.Json/Linq/JObject.cs
+++ b/Src/Newtonsoft.Json/Linq/JObject.cs
@@ -381,6 +381,7 @@ namespace Newtonsoft.Json.Linq
///
/// Gets the with the specified property name.
///
+ /// Name of the property.
/// The with the specified property name.
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 will be used to match a property.
///
+ /// Name of the property.
+ /// One of the enumeration values that specifies how the strings will be compared.
/// The with the specified property name.
public JToken GetValue(string propertyName, StringComparison comparison)
{
diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
index 942d9c05..715b0c5c 100644
--- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
@@ -90,7 +90,7 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
#if !PocketPC
-[assembly: AssemblyFileVersion("4.5.9.15402")]
+[assembly: AssemblyFileVersion("4.5.10.15427")]
#endif
[assembly: CLSCompliant(true)]
diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
index 9216977a..3d1928fe 100644
--- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
@@ -709,7 +709,7 @@ namespace Newtonsoft.Json.Utilities
{
T[] attributes = GetAttributes(attributeProvider, inherit);
- return attributes.SingleOrDefault();
+ return (attributes != null) ? attributes.SingleOrDefault() : null;
}
#if !(NETFX_CORE)
diff --git a/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs b/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs
index b4903e9f..acd94211 100644
--- a/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs
+++ b/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs
@@ -28,6 +28,7 @@ using System.Collections.Generic;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#endif
+using System.Threading;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
@@ -44,13 +45,11 @@ namespace Newtonsoft.Json.Utilities
throw new ArgumentNullException("creator");
_creator = creator;
+ _store = new Dictionary();
}
public TValue Get(TKey key)
{
- if (_store == null)
- return AddValue(key);
-
TValue value;
if (!_store.TryGetValue(key, out value))
return AddValue(key);
@@ -79,6 +78,7 @@ namespace Newtonsoft.Json.Utilities
Dictionary newStore = new Dictionary(_store);
newStore[key] = value;
+ Thread.MemoryBarrier();
_store = newStore;
}