Object serialization is a fundamental requirement in modern software development, particularly for data transmission and storage. In the .NET ecosystem, developers often choose between built-in libraries and third-party solutions. This analysis benchmarks three common approaches: JavaScriptSerializer, DataContractJsonSerializer, and the widely adopted Newtonsoft.Json (Json.NET) library. We will examine their efficiency in handling both strongly typed objects and loosely typed DataTable structures.
1. Library Dependencies and Setup
Before implementing the benchmark, ensure the necessary namespaces and assemblies are referenced in your project.
- JavaScriptSerializer: Located in
System.Web.Script.Serialization. Requires a reference toSystem.Web.Extensions.dll. - DataContractJsonSerializer: Part of
System.Runtime.Serialization.Json. Requires a reference toSystem.Runtime.Serialization.dll. - Newtonsoft.Json: A third-party library available via NuGet. Its the industry standard for JSON handling in .NET.
2. Serialization Helper Implementation
To standardize the testing process, wrapper methods have been created for the native .NET serializers. The code below refactors the logic into cleaner extension methods.
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web.Script.Serialization;
public static class SerializationExtensions
{
// DataContractJsonSerializer Wrappers
public static string ToDataContractJson<T>(this T obj)
{
try
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
catch
{
return string.Empty;
}
}
public static T FromDataContractJson<T>(this string json)
{
try
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
return (T)serializer.ReadObject(ms);
}
}
catch
{
return default(T);
}
}
// JavaScriptSerializer Wrappers
public static string ToLegacyJson<T>(this T obj)
{
try
{
var serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
catch
{
return string.Empty;
}
}
public static T FromLegacyJson<T>(this string json)
{
try
{
var serializer = new JavaScriptSerializer();
return serializer.Deserialize<T>(json);
}
catch
{
return default(T);
}
}
}
For Newtonsoft.Json, the native static methods JsonConvert.SerializeObject and JsonConvert.DeserializeObject are used directly without custom wrappers.
3. Test Data Generation
The benchmark utilizes two data sources: a collection of strongly typed objects and a DataTable. The methods below generate the test datasets.
using System;
using System.Collections.Generic;
using System.Data;
public class DataFactory
{
public static List<User> GenerateUserList(int count)
{
var list = new List<User>();
for (int i = 0; i < count; i++)
{
list.Add(new User
{
Name = "User_" + i,
Age = 20 + (i % 10),
IsActive = i % 5 == 0,
FieldA = i.ToString(),
FieldB = i.ToString(),
FieldC = i.ToString()
// Additional properties omitted for brevity
});
}
return list;
}
public static DataTable GenerateDataTable(int count)
{
var table = new DataTable("SampleTable");
table.Columns.Add("ID", typeof(int));
table.Columns.Add("FullName", typeof(string));
table.Columns.Add("Role", typeof(string));
for (int i = 0; i < count; i++)
{
var row = table.NewRow();
row["ID"] = i + 1;
row["FullName"] = "Name" + i;
row["Role"] = i % 2 == 0 ? "Admin" : "User";
table.Rows.Add(row);
}
return table;
}
}
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsActive { get; set; }
public string FieldA { get; set; }
public string FieldB { get; set; }
public string FieldC { get; set; }
}
4. Benchmark Execution Logic
The following code implements the performance test using System.Diagnostics.Stopwatch to measure execution time for both serialization and deserialization operations on a large dataset.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
const int itemCount = 50000;
var sourceData = DataFactory.GenerateUserList(itemCount);
Console.WriteLine($"--- Testing Strongly Typed Objects (Count: {itemCount}) ---\n");
// Test 1: JavaScriptSerializer
RunBenchmark("JavaScriptSerializer", sourceData,
data => data.ToLegacyJson(),
json => json.FromLegacyJson<User>());
// Test 2: DataContractJsonSerializer
RunBenchmark("DataContractJsonSerializer", sourceData,
data => data.ToDataContractJson(),
json => json.FromDataContractJson<User>());
// Test 3: Newtonsoft.Json
RunBenchmark("Newtonsoft.Json", sourceData,
data => JsonConvert.SerializeObject(data),
json => JsonConvert.DeserializeObject<User>(json));
Console.ReadLine();
}
public static void RunBenchmark<T>(string libraryName, List<T> originalData,
Func<T, string> serializeFunc, Func<string, T> deserializeFunc)
{
var serializedStrings = new List<string>();
var deserializedData = new List<T>();
// Serialization Phase
var watch = Stopwatch.StartNew();
foreach (var item in originalData)
{
serializedStrings.Add(serializeFunc(item));
}
watch.Stop();
Console.WriteLine($"[{libraryName}] Serialization of {originalData.Count} items took: {watch.ElapsedMilliseconds} ms");
// Deserialization Phase
watch.Restart();
foreach (var jsonStr in serializedStrings)
{
deserializedData.Add(deserializeFunc(jsonStr));
}
watch.Stop();
Console.WriteLine($"[{libraryName}] Deserialization of {serializedStrings.Count} items took: {watch.ElapsedMilliseconds} ms\n");
}
}
5. Performance Analysis Results
Testing was conducted with varying data volumes to observe scalability. The findings are summarized below:
Strongly Typed Objects
- Small Datasets (100 - 1,000 items): Performance differences between the three libraries are negligible. Execution times are nearly identical.
- Large Datasets (>10,000 items): Significant discrepancies emerge.
JavaScriptSerializershows a marked decrease in efficiency as data volume increases. BothDataContractJsonSerializerandNewtonsoft.Jsonmaintain superior performance, withNewtonsoft.Jsonoften showing a slight edge in speed.
Weakly Typed DataTable
- JavaScriptSerializer: This method frequently encounters errors or requires complex handling when attempting to serialize
DataTablestructures directly. - DataContractJsonSerializer: While capable, this serializer often converts
DataTablestructures into an XML-like JSON format or requires explicit configuration for table names, making it less intuitive for standard JSON data exchange. - Newtonsoft.Json: This library handles
DataTableserialization seamlessly, producing standard JSON that is easy to consume and parse.
Conclusion
For most modern .NET applications, Newtonsoft.Json offers the best balance of performance and ease of use, particularly when dealing with complex structures like DataTable or large volumes of data. While DataContractJsonSerializer is a viable native alternative, JavaScriptSerializer should generally be avoided for performance-critical or large-scale operations due to its degradation in speed as dataset size increases.