一次修改闭源 Entity Provider 程序集以兼容新 EntityFramework 的过程
读完本文你会知道,如何在没有源码的情况下,直接修改一个 DLL 以去除 DLL 上的强命名限制,并在该程序集上直接添加你的“友元程序集(一种特殊的 Attribute,将它应用在程序集上,使得程序集内的 internal 类型能够被其它程序集直接调用)”。以此类推,你可以用此方法,直接修改程序集,达到想要的目的。
银行的一个项目,客户要求使用他们现有的的 Teradata 数据库,项目组第一个想到的是 NHibernate ,但是几乎没有找到关于 NHibernate 支持 Teradata 数据库的资料,于是把问题抛给了我。
我也没有找到相关资料,奇怪的是 Java 版 hibernate 是支持 Teradata 的,为什么 NHibernate 当年移植的时候没有做 Teradata dialect 的移植?是因为有技术上的限制吗?我一方面在 NHibernate 官方 Group 里表达了这个疑问,一方面发现 Entity Framework 是支持 Teradata 数据库的,把这个消息告知了项目组。
第二天,看到 NHibernate Group 里面有回复了,“或许只因为是没有人实现它”。这样我也打消了最后的顾虑,自己参考 Java 版 hibernate teradata dialect 做了个 NHibernate 版的实现,由于没有项目组 teradata 数据库的特定环境,只能发给项目组他们去做测试了。我之所以坚持使用 NHibernate ,是因为公司的框架有在 NHibernate 上的成熟封装,如果换用 EntityFramework ,需要做适配。
最后项目组决定用 EntityFramework ,但又希望使用最新版的 EntityFramework,却又发现最新版的 EntityFramework 6.1 对 Teradata 的支持存在问题,于是把问题抛给了我。
分析了一下,原因并不是 EntityFramework 不兼容 Teradata,EntityFramework 支持多数据库的原理是把数据库通用的地方抽象出来,然后去做不同数据库的实现(Entity Provider),有的数据库实现是 EntityFramework 官方提供的(如 SQL Server Entity Provider),Teradata 数据库官方提供了对 EntityFramework 的支持,但可能是由于后来 EntityFramework 做了改动,导致老的 Teradata Entity Provider 已经无法在 EntityFramework 6.1 上正常使用了,Teradata 官方也没有及时更新 Provider。
好了,抛开任何杂念,本着研究一下的态度,试一下吧:
|
Teradata for .NET 涉及到的 dll |
|
|
Teradata.Client.Provider.dll |
Teradata 数据库的底层驱动。此程序集采用强命名。并对下面的 Teradata.Client.Entity.dll 友元(就是这个程序集里面的内部类对友元程序集可见,Teradata.Client.Provider.dll 里面的内部类对 Teradata.Client.Entity.dll 可见)。 |
|
Teradata.Client.Entity.dll |
引用 Teradata.Client.Provider.dll 。Teradata 的 EntityFramework Provider,实现了 EntityFramework 规定的接口,这样 EntityFramework 就可以使用它操纵 Teradata 数据库。 |
Solution A:
试着在它原来的 Entity Provider 上包装一层,来兼容新版本的 EntityFramework , 实践证明行不通,虽然代码看上去差不多,但新版的 EntityFramework 将大量类的命名空间、程序集都改掉了,没有办法处理这些新老类型之间的转换。所以放弃了这个方案。
Solution B:
修改 Teradata.Client.Entity.dll (Entity Provider) 源代码来兼容新 EntityFramework 。
网上没有源码,通过反编译拿到了 Teradata.Client.Entity.dll 的 Source Code ,编译 Source Code 报了十几个错,不过还好都能够修正。最反编译出的代码已经没有错误了。
但是编译还是不通过,因为 Teradata.Client.Entity.dll 是 Teradata.Client.Provider.dll 的友元程序集,Teradata.Client.Entity.dll 直接引用了 Teradata.Client.Provider.dll 里面的内部类,而 Teradata.Client.Provider.dll 指定的友元程序集是强命名的 Teradata.Client.Entity.dll,反编译后的 Teradata.Client.Entity.dll 丢失了强命名,编译的时候不通过。
[图 Teradata.Client.Provider.dll 指定的友元程序集是强命名的 Teradata.Client.Entity.dll]

有两个解决办法:
1.反编译 Teradata.Client.Provider.dll ,拿到源码,去掉对 Teradata.Client.Entity.dll 的强命名友元,然后编译。(经尝试反编译后大量报错,放弃)
2.直接用工具修改 Teradata.Client.Provider.dll ,将里面对 Teradata.Client.Entity.dll 的强命名友元改为弱命名友元。
那么试二个办法:
1.在 Developer Command Prompt for VS2013 命令提示符中输入如下命令
:: 反编译 DLL 得到 IL
ildasm Teradata.Client.Provider.dll /output=i.il
打开找到里面的:
.assembly Teradata.Client.Provider
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.InternalsVisibleToAttribute::.ctor(string) = (
01 00 81 62 54 65 72 61 64 61 74 61 2E 43 6C 69 // ...bTeradata.Cli
65 6E 74 2E 45 6E 74 69 74 79 2C 20 50 75 62 6C // ent.Entity, Publ
69 63 4B 65 79 3D 30 30 32 34 30 30 30 30 30 34 // icKey=0024000004
38 30 30 30 30 30 39 34 30 30 30 30 30 30 30 36 // 8000009400000006
30 32 30 30 30 30 30 30 32 34 30 30 30 30 35 32 // 0200000024000052
35 33 34 31 33 31 30 30 30 34 30 30 30 30 30 31 // 5341310004000001
30 30 30 31 30 30 63 39 66 63 62 31 62 35 33 36 // 000100c9fcb1b536
61 65 36 31 31 30 32 61 37 30 36 61 31 65 38 30 // ae61102a706a1e80
31 65 36 32 65 64 34 37 35 39 32 37 39 36 34 35 // 1e62ed4759279645
37 65 30 36 33 36 39 61 63 61 63 31 34 62 65 66 // 7e06369acac14bef
38 34 66 65 36 61 33 32 39 39 34 36 34 31 34 63 // 84fe6a329946414c
39 65 30 35 65 32 65 62 66 65 64 66 30 36 61 66 // 9e05e2ebfedf06af
33 66 39 36 32 37 36 64 34 32 31 35 32 38 30 37 // 3f96276d42152807
36 39 35 37 63 35 30 32 33 35 63 36 65 38 31 37 // 6957c50235c6e817
64 62 64 34 37 66 64 32 35 66 35 37 37 33 61 34 // dbd47fd25f5773a4
62 62 65 62 31 30 61 62 65 65 61 38 36 34 36 31 // bbeb10abeea86461
33 34 33 34 66 34 39 63 38 36 30 63 35 34 32 38 // 3434f49c860c5428
31 31 66 36 35 61 30 38 35 65 35 33 34 65 65 34 // 11f65a085e534ee4
34 38 37 33 37 31 33 31 61 37 64 38 62 31 33 63 // 48737131a7d8b13c
34 34 33 33 34 63 39 36 63 37 61 35 39 38 65 36 // 44334c96c7a598e6
65 65 36 38 65 63 61 66 64 34 66 37 63 61 31 33 // ee68ecafd4f7ca13
38 37 33 33 38 37 35 34 64 65 61 38 65 36 33 30 // 87338754dea8e630
31 61 66 65 63 38 00 00 ) // 1afec8..
…..
}
PublickKey 后面的就是强命名的 Public Key 了,用编辑器删掉它:
.custom instance void [mscorlib]System.Runtime.CompilerServices.InternalsVisibleToAttribute::.ctor(string) = (
01 00 16 54 65 72 61 64 61 74 61 2E 43 6C 69 65 // ...Teradata.Clie
6E 74 2E 45 6E 74 69 74 79 00 00 ) // nt.Entity..
这样 Teradata.Client.Provider.dll 对 Teradata.Client.Entity.dll 的友元就不是强命名的了。
然后接着在 Developer Command Prompt for VS2013 命令提示符中输入如下命令:
:: 将 IL 编译为 DLL
ilasm.exe i.il /DLL /OUTPUT=Teradata.Client.Provider.dll
[图 修改后]

这样 Teradata.Client.Entity.dll 就能编译通过了,这还不算完,还需要将 Teradata.Client.Entity.dll 里面的老的 EntityFramework Provider 实现修改为新实现(基本上批量替换一下命名空间就可以了)。
最后添加到项目中去重新引用,修改 .config 中的 EntityFramework Entity Provider 为我们刚才反编译得到的项目里面的实现了 EntityFramework Provider 的类:“Teradata.Client.Entity.TdProviderServices, Teradata.Client.Entity”
运行项目。
最后,我认为比知道如何解决一个问题更重要的,是解决问题的思路,比思路更重要的,是遇到大大小小各种棘手、麻烦、混乱的问题时候仍然淡定的心态。
一次修改闭源 Entity Provider 程序集以兼容新 EntityFramework 的过程的更多相关文章
- 修改spring源码重写classloader实现项目加密
(一)操作方法和spring源码添加修改部分 事先说明:spring源码要下载好,会有修改spring的源码操作,本文和本作者所依赖的spring项目的版本是3.1.1,spring4及以上源码对 ...
- Eureka 2.0 闭源--选择Consul???
在上个月我们知道 Eureka 2.0 闭源了,但其实对国内的用户影响甚小,一方面国内大都使用的是 Eureka 1.X 系列,另一方面 Spring Cloud 支持很多服务发现的软件,Eureka ...
- 使用Docker Toolbox基于boot2docker搭建的Docker如何修改镜像源
镜像源 由于众所周知的原因,我们直接连接这些位于国外服务器上的仓库去获取依赖包速度是非常慢的,这时候我们通常会采用国内一些组织或开发者贡献的国内镜像仓库. 1.首先Docker也提供了国内的镜像源:h ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_3-04 SpringCloud微服务核心组件Eureka介绍和闭源后影响
笔记 4.SpringCloud微服务核心组件Eureka介绍和闭源后影响 简介: SpringCloud体系介绍 官方地址:http://projec ...
- Eureka 2.0 闭源--选择Consul???[转]
原文链接: https://www.cnblogs.com/williamjie/p/9369800.html 在上个月我们知道 Eureka 2.0 闭源了,但其实对国内的用户影响甚小,一方面国内大 ...
- Docker与k8s的恩怨情仇(四)-云原生时代的闭源落幕
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在本系列前几篇文章中,我们介绍了从Cloud Foundry到Docker等PaaS平台的发展迭代过程.今天 ...
- 20161117__修改yum源
1.CentOS6.5中修改yum源 http://www.cnblogs.com/liuling/p/2014-4-14-001.html 在自己安装的CentOS6.5中使用yum安装软件,总是提 ...
- Linux开源系统对比Windows闭源系统的优势解析
当我们听到linux的时候是不是觉得高大上的感觉呢?在我刚上大学的时候,听着学长们给我讲他们的大学的学习经历,先学习C语言.单片机.然后做一些项目,现在正学习linux操作系统,当我听到linux操作 ...
- CentOS6.5修改yum源
在安装完CentOS后一般需要修改yum源,才能够在安装更新rpm包时获得比较理想的速度.国内比较快的有163源.sohu源.这里以163源为例子. 1, cd /etc/yum.repos.d 2. ...
随机推荐
- CYQ.Data、ASP.NET Aries 百家企业使用名单
如果您或您所在的公司正在使用此框架,请联系左侧的扣扣,告知我信息,我将为您添加链接: 以下内容为已反馈的用户,(收集始于:2016-08-08),仅展示99家: 序号 企业名称 企业网址 备注 1 山 ...
- Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制
将通用的序列号生成器库 从SQL Server迁移到Mysql 遇到的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现.SQ ...
- 黑云压城城欲摧 - 2016年iOS公开可利用漏洞总结
黑云压城城欲摧 - 2016年iOS公开可利用漏洞总结 作者:蒸米,耀刺,黑雪 @ Team OverSky 0x00 序 iOS的安全性远比大家的想象中脆弱,除了没有公开的漏洞以外,还有很多已经公开 ...
- SQL Server 常用内置函数(built-in)持续整理
本文用于收集在运维中经常使用的系统内置函数,持续整理中 一,常用Metadata函数 1,查看数据库的ID和Name db_id(‘DB Name’),db_name('DB ID') 2,查看对象的 ...
- c#多线程
一.使用线程的理由 1.可以使用线程将代码同其他代码隔离,提高应用程序的可靠性. 2.可以使用线程来简化编码. 3.可以使用线程来实现并发执行. 二.基本知识 1.进程与线程:进程作为操作系统执行程序 ...
- javascript 判断参数类型大全
js 判断类型的在开发中是很常用的,因为js 是弱类型的语言,var 可以接受任何形式的类型,但是在真正的开发中,我们需要根据不同类型做不同的处理,所以这个是必须的精通. 首先需要知道 typeof这 ...
- 如果你也会C#,那不妨了解下F#(7):面向对象编程之继承、接口和泛型
前言 面向对象三大基本特性:封装.继承.多态.上一篇中介绍了类的定义,下面就了解下F#中继承和多态的使用吧.
- 通过自定义特性,使用EF6拦截器完成创建人、创建时间、更新人、更新时间的统一赋值(使用数据库服务器时间赋值,接上一篇)
目录: 前言 设计(完成扩展) 实现效果 扩展设计方案 扩展后代码结构 集思广益(问题) 前言: 在上一篇文章我写了如何重建IDbCommandTreeInterceptor来实现创建人.创建时间.更 ...
- Web开发安全之文件上传安全
很长一段时间像我这种菜鸡搞一个网站第一时间反应就是找上传,找上传.借此机会把文件上传的安全问题总结一下. 首先看一下DVWA给出的Impossible级别的完整代码: <?php if( iss ...
- React Native环境配置之Windows版本搭建
接近年底了,回想这一年都做了啥,学习了啥,然后突然发现,这一年买了不少书,看是看了,就没有完整看完的.悲催. 然后,最近项目也不是很紧了,所以抽空学习了H5.自学啃书还是很无趣的,虽然Head Fir ...