欢迎投稿

今日深度:

一次修改闭源 Entity Provider 程序集以兼容新 EntityFramework 的过程,

一次修改闭源 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]

 图 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”

运行项目。

 

最后,我认为比知道如何解决一个问题更重要的,是解决问题的思路,比思路更重要的,是遇到大大小小各种棘手、麻烦、混乱的问题时候仍然淡定的心态。

www.htsjk.Com true http://www.htsjk.com/teradata/27250.html NewsArticle 一次修改闭源 Entity Provider 程序集以兼容新 EntityFramework 的过程, 读完本文你会知道,如何在没有源码的情况下,直接修改一个 DLL 以去除 DLL 上的强命名限制,并在该程序集上直接添加...
相关文章
    暂无相关文章
评论暂时关闭