Last active
August 29, 2015 14:19
-
-
Save randyburden/22f6e87a8964ccc865fe to your computer and use it in GitHub Desktop.
Provides methods for serializing and deserializing JSON by using the Newtonsoft.Json aka JSON.NET library which is loaded dynamically via reflection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Reflection; | |
| namespace ReflectionExample | |
| { | |
| /// <summary> | |
| /// Provides methods for serializing and deserializing JSON by using the Newtonsoft.Json aka JSON.NET library | |
| /// which is loaded dynamically via reflection. | |
| /// </summary> | |
| /// <remarks> | |
| /// This class allows you to not have to have a direct dependency on JSON.NET in your code. Since JSON.NET is | |
| /// a strongly named assembly you can end up having to add binding redirects if your project references multiple | |
| /// projects which each reference different versions of JSON.NET. | |
| /// </remarks> | |
| public class DynamicallyLoadedJsonNetSerializer | |
| { | |
| private readonly MethodInfo _serializeObject; | |
| private readonly MethodInfo _deserializeObject; | |
| private readonly Array _jsonConverters; | |
| public DynamicallyLoadedJsonNetSerializer() | |
| { | |
| var newtonSoftJson = Assembly.Load( "Newtonsoft.Json" ); | |
| if ( newtonSoftJson == null ) | |
| throw new JsonNetDynamicLoadException( "Newtonsoft.Json aka JSON.NET is not loaded. Please add a reference to Newtonsoft.Json." ); | |
| var jsonConvert = newtonSoftJson.GetType( "Newtonsoft.Json.JsonConvert", throwOnError: false ); | |
| if ( jsonConvert == null ) | |
| throw new JsonNetDynamicLoadException( "Could not load class Newtonsoft.Json.JsonConvert." ); | |
| var jsonConverter = newtonSoftJson.GetType( "Newtonsoft.Json.JsonConverter", throwOnError: false ); | |
| if ( jsonConverter == null ) | |
| throw new JsonNetDynamicLoadException( "Could not load class Newtonsoft.Json.JsonConverter." ); | |
| _jsonConverters = Array.CreateInstance( jsonConverter, 2 ); | |
| var isoDateTimeConverterType = newtonSoftJson.GetType( "Newtonsoft.Json.Converters.IsoDateTimeConverter", throwOnError: false ); | |
| if( isoDateTimeConverterType == null ) | |
| throw new JsonNetDynamicLoadException( "Could not load class Newtonsoft.Json.Converters.IsoDateTimeConverter." ); | |
| var isoDateTimeConverter = Activator.CreateInstance( isoDateTimeConverterType ); | |
| _jsonConverters.SetValue( isoDateTimeConverter, 0 ); | |
| var stringEnumConverterType = newtonSoftJson.GetType( "Newtonsoft.Json.Converters.StringEnumConverter", throwOnError: false ); | |
| if( stringEnumConverterType == null ) | |
| throw new JsonNetDynamicLoadException( "Could not load class Newtonsoft.Json.Converters.StringEnumConverter." ); | |
| var stringEnumConverter = Activator.CreateInstance( stringEnumConverterType ); | |
| _jsonConverters.SetValue( stringEnumConverter, 1 ); | |
| _serializeObject = jsonConvert.GetMethod( "SerializeObject", new Type[] { typeof ( object ), _jsonConverters.GetType() } ); | |
| if ( _serializeObject == null ) | |
| throw new JsonNetDynamicLoadException( "Could not locate method: Newtonsoft.Json.JsonConvert.SerializeObject( object value, params JsonConverter[] converters )" ); | |
| _deserializeObject = jsonConvert.GetMethod( "DeserializeObject", new Type[] { typeof ( string ), typeof ( Type ), _jsonConverters.GetType() } ); | |
| if ( _deserializeObject == null ) | |
| throw new JsonNetDynamicLoadException( "Could not locate method: Newtonsoft.Json.JsonConvert.DeserializeObject( string value, Type type, params JsonConverter[] converters )" ); | |
| } | |
| public string Serialize( object obj ) | |
| { | |
| return ( string ) _serializeObject.Invoke( null, new[] { obj, _jsonConverters } ); | |
| } | |
| public T Deserialize<T>( string input ) | |
| { | |
| return ( T ) Deserialize( input, typeof ( T ) ); | |
| } | |
| public object Deserialize( string input, Type type ) | |
| { | |
| return _deserializeObject.Invoke( null, new object[] { input, type, _jsonConverters } ); | |
| } | |
| public class JsonNetDynamicLoadException : Exception | |
| { | |
| public JsonNetDynamicLoadException( string message ) | |
| : base( message ) | |
| { | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using Newtonsoft.Json; | |
| using Newtonsoft.Json.Converters; | |
| using NUnit.Framework; | |
| namespace ReflectionExample.Tests | |
| { | |
| [TestFixture] | |
| public class DynamicallyLoadedJsonNetSerializerTests | |
| { | |
| [Test] | |
| public void CanSerializeToJson() | |
| { | |
| // Arrange | |
| var person = new Person { PersonId = 1, FirstName = "Bob", LastName = "Smith", DateOfBirth = DateTime.Parse( "2015-04-23T17:11:21.1505595-05:00" ) }; | |
| // Act | |
| var json = new DynamicallyLoadedJsonNetSerializer().Serialize( person ); | |
| // Visual Assertion | |
| Trace.WriteLine( json ); | |
| // Assert | |
| Assert.That( json == "{\"PersonId\":1,\"FirstName\":\"Bob\",\"LastName\":\"Smith\",\"DateOfBirth\":\"2015-04-23T17:11:21.1505595-05:00\"}" ); | |
| } | |
| [Test] | |
| public void CanDeserializeJsonToType() | |
| { | |
| // Arrange | |
| const string json = "{\"PersonId\":1,\"FirstName\":\"Bob\",\"LastName\":\"Smith\",\"DateOfBirth\":\"2015-04-23T17:11:21.1505595-05:00\"}"; | |
| // Act | |
| var person = new DynamicallyLoadedJsonNetSerializer().Deserialize<Person>( json ); | |
| // Visual Assertion | |
| Trace.WriteLine( "PersonId: " + person.PersonId ); | |
| Trace.WriteLine( "FirstName: " + person.FirstName ); | |
| Trace.WriteLine( "LastName: " + person.LastName ); | |
| Trace.WriteLine( "DateOfBirth: 1" + person.DateOfBirth.ToUniversalTime() ); | |
| // Assert | |
| Assert.That( person.PersonId == 1 ); | |
| Assert.That( person.FirstName == "Bob" ); | |
| Assert.That( person.LastName == "Smith" ); | |
| Assert.That( person.DateOfBirth == DateTime.Parse( "2015-04-23T17:11:21.1505595-05:00" ) ); | |
| } | |
| [Test] | |
| public void SerializationPerformanceComparison() | |
| { | |
| var stopwatch = Stopwatch.StartNew(); | |
| for ( int i = 0; i < 500000; i++ ) | |
| { | |
| var person = new Person { PersonId = 1, FirstName = "Bob", LastName = "Smith", DateOfBirth = DateTime.Parse( "2015-04-23T17:11:21.1505595-05:00" ) }; | |
| var json = JsonConvert.SerializeObject( person, new IsoDateTimeConverter(), new StringEnumConverter() ); | |
| } | |
| Trace.WriteLine( stopwatch.ElapsedMilliseconds ); | |
| var serializer = new DynamicallyLoadedJsonNetSerializer(); | |
| stopwatch = Stopwatch.StartNew(); | |
| for( int i = 0; i < 500000; i++ ) | |
| { | |
| var person = new Person { PersonId = 1, FirstName = "Bob", LastName = "Smith", DateOfBirth = DateTime.Parse( "2015-04-23T17:11:21.1505595-05:00" ) }; | |
| var json = serializer.Serialize( person ); | |
| } | |
| Trace.WriteLine( stopwatch.ElapsedMilliseconds ); | |
| } | |
| [Test] | |
| public void DeserializationPerformanceComparison() | |
| { | |
| var stopwatch = Stopwatch.StartNew(); | |
| for( int i = 0; i < 500000; i++ ) | |
| { | |
| const string json = "{\"PersonId\":1,\"FirstName\":\"Bob\",\"LastName\":\"Smith\",\"DateOfBirth\":\"2015-04-23T17:11:21.1505595-05:00\"}"; | |
| var person = JsonConvert.DeserializeObject<Person>( json, new IsoDateTimeConverter(), new StringEnumConverter() ); | |
| } | |
| Trace.WriteLine( stopwatch.ElapsedMilliseconds ); | |
| var serializer = new DynamicallyLoadedJsonNetSerializer(); | |
| stopwatch = Stopwatch.StartNew(); | |
| for( int i = 0; i < 500000; i++ ) | |
| { | |
| const string json = "{\"PersonId\":1,\"FirstName\":\"Bob\",\"LastName\":\"Smith\",\"DateOfBirth\":\"2015-04-23T17:11:21.1505595-05:00\"}"; | |
| var person = serializer.Deserialize<Person>( json ); | |
| } | |
| Trace.WriteLine( stopwatch.ElapsedMilliseconds ); | |
| } | |
| public class Person | |
| { | |
| public int PersonId; | |
| public string FirstName; | |
| public string LastName; | |
| public DateTime DateOfBirth; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Performance Tests
Conclusion: After running both the serialization and deserialization methods over 500k iterations ( see unit tests ), the performance differences between a direct method call of the JsonConvert class compared to the DynamicallyLoadedJsonNetSerializer class which uses reflection shows less than a 1 second difference thus I would conclude that the performance penalty incurred using reflection is so negligible that it doesn't really matter.
SerializationPerformanceComparison
DeserializationPerformanceComparison
Tests ran on a Intel i7-3740QM Quad Core 2.7 GHz