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

一种优雅的条件引用第三方.net库的方法的更多相关文章

  1. 【Angular】关于angular引用第三方组件库无法改变其组件样式 :host ::ng-deep

    [Angular]关于angular引用第三方组件库无法改变其组件样式 :host ::ng-deep css修改:无效 .ant-input-affix-wrapper .ant-input:not ...

  2. 如何在 FineUIMvc 中引用第三方 JavaScript 库

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 引入第三方颜色选择器 在 FineUIMvc 中使用第三方 JavaScript 遵循一定的约定,也非常简单. 下面以官网示例为 ...

  3. ionic3.0--angular4.0 引入第三方插件库的方法

    ionic3.0 引入第三方插件 (swiper),方法很多,现详细说明下官方推荐(typings)做法. 1.全局安装Typings 1. npm install -g typings  2.搜索你 ...

  4. Use Swift Dynamic Framework (如何科学地引用第三方 Swift 库)

    转自:http://andelf.github.io/blog/2014/07/07/use-swift-dynamic-library/ CocoaPods 由于完全使用静态链接解决方法,过度依赖 ...

  5. css引用第三方字体库

    对应的CSS文件中如下方式进行字体库的引用: @font-face { font-family: '造字工房情书'; src: url('../fonts/MFQingShu_Noncommercia ...

  6. Xamarin引用第三方包错误解决方法

    http://www.cnblogs.com/ThenDog/p/7623720.html

  7. 解决vue webApp使用lib-flexible和px2rem引用第三方ui库后,样式变小问题

    首先,需要卸载项目中的postcss-px2rem. npm uninstall postcss-px2rem --save-dev 其次,安装postcss-px2rem-exclude npm i ...

  8. NDK 链接第三方静态库的方法

    将NDK编译的第三方静态拷贝到JNI目录下,在Android.mk中添加如下代码 以openssl静态库(libcrypto-static.a)为例 第一种链接方法:LOCAL_LDFLAGS := ...

  9. vs增加第三方依赖库的方法总结

    转自http://blog.csdn.net/raodotcong/article/details/8998379 先说说普通的两种方法: 方法1:  通过设置工程配置来添加lib库. 转自网上: A ...

随机推荐

  1. 前端CSS的工程化——掌握Sass这四大特性就够了

    初遇 CSS,一见倾心 记得刚遇见css的时候,咱像是见了美人儿一样,简直是爱不释手啊,简简单单写几行算不上代码的代码,就能做出这么漂亮的东西,这也成了咱前端之路的最初动力. 然而,随着项目体量和页面 ...

  2. 为什么要初始化CSS?

    因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异. 当然,初始化样式会对SEO有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下 ...

  3. WeChat 隐私政策

    隐私政策 本应用尊重并保护所有使用服务用户的个人隐私权.为了给您提供更准确.更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息.但本应用将以高度的勤勉.审慎义务对待这些信息.除本隐 ...

  4. java 之 桥接模式(大话设计模式)

    桥接模式定义为:将抽象部分与它的实现部分分离,使它们都可以独立的变化. 第一次看设计模式的时候,不是很清楚这句话的意思,随着笔者的不断开发,发现有一种场景, 继承关系多了,不易于维护父类,而笔者认为桥 ...

  5. python爬虫(五)_urllib2:Get请求和Post请求

    本篇将介绍urllib2的Get和Post方法,更多内容请参考:python学习指南 urllib2默认只支持HTTP/HTTPS的GET和POST方法 urllib.urlencode() urll ...

  6. Python爬虫:用BeautifulSoup进行NBA数据爬取

    爬虫主要就是要过滤掉网页中没用的信息.抓取网页中实用的信息 一般的爬虫架构为: 在python爬虫之前先要对网页的结构知识有一定的了解.如网页的标签,网页的语言等知识,推荐去W3School: W3s ...

  7. Asteroids!-裸的BFS

    G - Asteroids! Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Subm ...

  8. RxJava开发精要6 - 组合Observables

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发人员头条享有独家 ...

  9. 通过案例学习 Secret - 每天5分钟玩转 Docker 容器技术(110)

    在下面的例子中,我们会部署一个 WordPress 应用,WordPress 是流行的开源博客系统. 我们将创建一个 MySQL service,将密码保存到 secret 中.我们还会创建一个 Wo ...

  10. oracle实现主键自增

    首先,创建一张表: CREATE TABLE example( ID Number(4) NOT NULL PRIMARY KEY, NAME VARCHAR(25)); 然后,自定义一个序列(seq ...