Skip to main content

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 )
            {
            }
        }
    }
}