using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PlayJsonSerializers
{
class Program
{
static void Main(string[] args)
{
Func<object,string> netJson = o => NetJSON.NetJSON.Serialize(o);
Func<object,string> jil = o => Jil.JSON.Serialize(o);
Func<object, string> ssText = o => ServiceStack.Text.JsonSerializer.SerializeToString(o);
// ASP.NET Web API default JSON serializer
Func<object, string> jsonNet = o => Newtonsoft.Json.JsonConvert.SerializeObject(o);
var aspNetWebMvcDefaultJsonSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
Func<object, string> javaScriptSerializer = o => aspNetWebMvcDefaultJsonSerializer.Serialize(o);
// To replace ASP.NET MVC JSON serializer: http://www.ienablemuch.com/2014/10/aspnet-mvc-return-json-without-using-jsonresult.html
var jsSerializers = new Dictionary<string, Func<object, string>>()
{
{ "NetJSON", netJson },
{ "Jil", jil },
{ "ServiceStack.Text", jil },
{ "Json.NET", jsonNet },
{ "ASP.NET MVC Default", javaScriptSerializer}
};
Action<string,object> benchmark = (description,o) =>
{
const string netJsonReplacedWithJsonNet = "NetJSON Replaced with Json.NET";
var fallbackJsonSerializer = jsonNet;
bool isAnonymousType = o.GetType().IsAnonymousType();
Console.WriteLine(description);
Console.WriteLine("Serialization");
foreach (var item in jsSerializers)
{
if (isAnonymousType && item.Key == "NetJSON")
fallbackJsonSerializer(o).Show(netJsonReplacedWithJsonNet);
else
item.Value(o).Show(item.Key);
}
Console.WriteLine("Speed");
foreach (var item in jsSerializers)
{
if (isAnonymousType && item.Key == "NetJSON")
ShowTime(netJsonReplacedWithJsonNet, delegate { for (int i = 0; i < 20000; i++) fallbackJsonSerializer(o); });
else
ShowTime(item.Key, delegate { for (int i = 0; i < 20000; i++) item.Value(o); });
}
Console.WriteLine(new string('-',80));
};
benchmark("Object with complete properties",
new Person { PersonId = 123456789, FirstName = "Linus", MiddleName = "Great", LastName = "Snoopy" });
benchmark("Object with null properties",
new Person { PersonId = 123456789, FirstName = "Linus", LastName = "Snoopy" });
benchmark("Object with inheritance",
new Employee { PersonId = 123456789, FirstName = "Linus", MiddleName = "Great", LastName = "Snoopy", IsActive = true });
benchmark("Anonymous object with complete properties",
new { PersonId = 123456789, FirstName = "Linus", MiddleName = "Great", LastName = "Snoopy", IsActive = true });
benchmark("Anonymous object. Property with inheritance",
new { Greet = "Hello", Employee = new Employee { PersonId = 123456789, FirstName = "Linus", MiddleName = "Great", LastName = "Snoopy", IsActive = true } });
}
static void ShowTime(string jsSerializer, Action task)
{
var sw = Stopwatch.StartNew();
task();
sw.Stop();
var milliseconds = (long)sw.ElapsedMilliseconds;
Console.WriteLine("{0, 30}: {1}", jsSerializer, milliseconds);
}
}
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public class Employee : Person
{
public bool IsActive { get; set; }
}
static class StringExtension
{
internal static void Show(this string s, string description = "")
{
Console.WriteLine("{0, 30}: {1}", description, s);
}
}
static class TypeExtension
{
// http://www.jefclaes.be/2011/05/checking-for-anonymous-types.html
static internal bool IsAnonymousType(this Type type)
{
Debug.Assert(type != null, "Type should not be null");
// HACK: The only way to detect anonymous types right now.
return Attribute.IsDefined(type, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false)
&& type.IsGenericType && type.Name.Contains("AnonymousType")
&& (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase) ||
type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase))
&& (type.Attributes & System.Reflection.TypeAttributes.NotPublic) == System.Reflection.TypeAttributes.NotPublic;
}
}
}
Results:
Object with complete properties
Serialization
NetJSON: {"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}
Jil: {"PersonId":123456789,"LastName":"Snoopy","MiddleName":"Great","FirstName":"Linus"}
ServiceStack.Text: {"PersonId":123456789,"LastName":"Snoopy","MiddleName":"Great","FirstName":"Linus"}
Json.NET: {"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}
ASP.NET MVC Default: {"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}
Speed
NetJSON: 38
Jil: 77
ServiceStack.Text: 89
Json.NET: 119
ASP.NET MVC Default: 1022
--------------------------------------------------------------------------------
Object with null properties
Serialization
NetJSON: {"PersonId":123456789,"FirstName":"Linus","LastName":"Snoopy"}
Jil: {"PersonId":123456789,"LastName":"Snoopy","MiddleName":null,"FirstName":"Linus"}
ServiceStack.Text: {"PersonId":123456789,"LastName":"Snoopy","MiddleName":null,"FirstName":"Linus"}
Json.NET: {"PersonId":123456789,"FirstName":"Linus","MiddleName":null,"LastName":"Snoopy"}
ASP.NET MVC Default: {"PersonId":123456789,"FirstName":"Linus","MiddleName":null,"LastName":"Snoopy"}
Speed
NetJSON: 28
Jil: 84
ServiceStack.Text: 75
Json.NET: 131
ASP.NET MVC Default: 1020
--------------------------------------------------------------------------------
Object with inheritance
Serialization
NetJSON: {"IsActive":true,"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}
Jil: {"IsActive":true}
ServiceStack.Text: {"IsActive":true}
Json.NET: {"IsActive":true,"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}
ASP.NET MVC Default: {"IsActive":true,"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}
Speed
NetJSON: 37
Jil: 53
ServiceStack.Text: 48
Json.NET: 148
ASP.NET MVC Default: 1307
--------------------------------------------------------------------------------
Anonymous object with complete properties
Serialization
NetJSON Replaced with Json.NET: {"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy","IsActive":true}
Jil: {"IsActive":true,"PersonId":123456789,"LastName":"Snoopy","MiddleName":"Great","FirstName":"Linus"}
ServiceStack.Text: {"IsActive":true,"PersonId":123456789,"LastName":"Snoopy","MiddleName":"Great","FirstName":"Linus"}
Json.NET: {"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy","IsActive":true}
ASP.NET MVC Default: {"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy","IsActive":true}
Speed
NetJSON Replaced with Json.NET: 156
Jil: 94
ServiceStack.Text: 111
Json.NET: 171
ASP.NET MVC Default: 1702
--------------------------------------------------------------------------------
Anonymous object. Property with inheritance
Serialization
NetJSON Replaced with Json.NET: {"Greet":"Hello","Employee":{"IsActive":true,"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}}
Jil: {"Employee":{"IsActive":true},"Greet":"Hello"}
ServiceStack.Text: {"Employee":{"IsActive":true},"Greet":"Hello"}
Json.NET: {"Greet":"Hello","Employee":{"IsActive":true,"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}}
ASP.NET MVC Default: {"Greet":"Hello","Employee":{"IsActive":true,"PersonId":123456789,"FirstName":"Linus","MiddleName":"Great","LastName":"Snoopy"}}
Speed
NetJSON Replaced with Json.NET: 222
Jil: 95
ServiceStack.Text: 103
Json.NET: 211
ASP.NET MVC Default: 2200
--------------------------------------------------------------------------------
Summary:
* NetJSON is the fastest
* Jil and ServiceStack can't serialize inherited classes
* NetJSON doesn't serialize null propeties, good optimization
As for replacing NetJSON with Json.NET, NetJSON can't serialize anonymous objects yet
Happy Coding!
No comments:
Post a Comment