Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Provides methods for serializing and deserializing JSON by using the Newtonsoft.Json aka JSON.NET library which is loaded dynamically via reflection.
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 )
{
}
}
}
}
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;
}
}
}
Owner

randyburden commented Apr 25, 2015

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
  • Direct Call: 4871 ms
  • Reflection: 5634 ms
DeserializationPerformanceComparison
  • Direct Call: 2651 ms
  • Reflection: 3249 ms

Tests ran on a Intel i7-3740QM Quad Core 2.7 GHz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment