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