1.遇到的問題
今年我一直在開發一個WebApiClient庫,旨在.net下能像java的retrofit一樣,方便地請求服務端的http接口。在這restful api盛行的年代,json的身影無處不在,.net framework自然也有json庫,System.Web.Script.Serialization.JavaScriptSerializer就是其中一個,但綜合性較好的,還是第三方的json.net。在開發WebApiClient過程中,我一直沒有依賴json.net,原因是:如果我的WebApiClient依賴json.net的版本是6.0,某個第三方庫ThirdLib依賴的json.net版本是7.0,在項目中會無法都使用WebApiClient和ThirdLib,原因是他們依賴的json.net版本不一樣而決生沖突,給使用者解決起來很非常麻煩。
2.期望的效果
我期望的效果是,如果引用WebApiClient庫的項目有使用到json.net,那么WebApiClient在json序列化時,就使用json.net,否則使用.net framework的System.Web.Script.Serialization.JavaScriptSerializer。這就要求我在開發WebApiClient的時候,不能直接引用json.net來開發,只能在運行時檢測應用程序域是否已加載了json.net,從而反射調用json.net來進行序列化。
想要的效果是這樣的
/// <summary> /// 反序列化對象 /// </summary> /// <param name="json">json</param> /// <param name="objType">對象類型</param> /// <returns></returns> public object Deserialize(string json, Type objType) { if (string.IsNullOrEmpty(json)) { return null; } if (JsonNet.IsSupported == true) { return JsonNet.DeserializeObject(json, objType); } var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); return serializer.Deserialize(json, objType); }
3.解決的方案
在運行時檢測應用程序域是否已加載了json.net,從而反射調用json.net來進行序列化。
實現中的難點:
1、如果檢測是否加載了Json.net
2、在檢測之后,才加載Json.net怎么辦
3、怎么樣減少反射的性能損耗
難點的解決:
1、使用AppDomain.CurrentDomain.GetAssemblies()方法獲取當前程序域目前已加載的程序集,判斷是否有Json.net的程序集;
2、監聽AppDomain.CurrentDomain.AssemblyLoad事件,訂閱新加載的程序集是否為Json.net的程序集;
3、將Newtonsoft.Json.JsonConvert的SerializeObject和DeserializeObject方法生成強類型委托,緩存起來等待調用;
完整代碼實現:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace WebApiClient { /// <summary> /// 提供Json.net無引用調用 /// </summary> static class JsonNet { /// <summary> /// Json.Net程序集名稱 /// </summary> private static readonly string jsonNetAssemblyName = "Newtonsoft.Json"; /// <summary> /// JsonConvert類名 /// </summary> private static readonly string jsonNetJsonConvertTypeName = "Newtonsoft.Json.JsonConvert"; /// <summary> /// 序列化方法的委托 /// </summary> private static Func<object, string> serializeFunc = null; /// <summary> /// 反序列化方法的委托 /// </summary> private static Func<string, Type, object> deserializeFunc = null; /// <summary> /// 獲取是否得到支持 /// </summary> public static bool IsSupported = false; /// <summary> /// Json.net /// </summary> static JsonNet() { AppDomain.CurrentDomain.AssemblyLoad += (s, e) => InitJsonNet(e.LoadedAssembly); InitJsonNet(AppDomain.CurrentDomain.GetAssemblies()); } /// <summary> /// 序列化對象 /// </summary> /// <param name="obj">對象</param> /// <returns></returns> public static string SerializeObject(object obj) { return JsonNet.serializeFunc.Invoke(obj); } /// <summary> /// 反序列化為對象 /// </summary> /// <param name="json">json文本</param> /// <param name="type">對象類型</param> /// <returns></returns> public static object DeserializeObject(string json, Type type) { return JsonNet.deserializeFunc.Invoke(json, type); } /// <summary> /// 初始化json.net /// </summary> /// <param name="assemblies">查找的程序集</param> private static void InitJsonNet(params Assembly[] assemblies) { if (JsonNet.IsSupported == true) { return; } var jsonNetAssembly = assemblies .FirstOrDefault(item => item.GetName().Name.Equals(jsonNetAssemblyName, StringComparison.OrdinalIgnoreCase)); if (jsonNetAssembly == null) { return; } var jsonConvertType = jsonNetAssembly.GetType(jsonNetJsonConvertTypeName, false); if (jsonConvertType == null) { return; } serializeFunc = CreateSerializeObjectFunc(jsonConvertType); deserializeFunc = CreateDeserializeObjectFunc(jsonConvertType); JsonNet.IsSupported = serializeFunc != null && deserializeFunc != null; } /// <summary> /// 創建SerializeObject方法的委托 /// </summary> /// <param name="classType">JsonConvert類型</param> /// <returns></returns> private static Func<object, string> CreateSerializeObjectFunc(Type classType) { var method = classType.GetMethod("SerializeObject", new[] { typeof(object) }); if (method == null) { return null; } return (Func<object, string>)method.CreateDelegate(typeof(Func<object, string>)); } /// <summary> /// 創建DeserializeObject方法的委托 /// </summary> /// <param name="classType">JsonConvert類型</param> /// <returns></returns> private static Func<string, Type, object> CreateDeserializeObjectFunc(Type classType) { var method = classType.GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) }); if (method == null) { return null; } return (Func<string, Type, object>)method.CreateDelegate(typeof(Func<string, Type, object>)); } } }
關於WebApiClient
這是一個讓你描述做什么請求,而不是叫你如何請求的httpClient客戶端項目,關注一下,你會眼前一亮,get到新思想。
github:https://github.com/xljiulang/WebApiClient