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

📅 2026/7/3 19:47:17
一次修改闭源 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 不兼容 TeradataEntityFramework 支持多数据库的原理是把数据库通用的地方抽象出来然后去做不同数据库的实现Entity Provider有的数据库实现是 EntityFramework 官方提供的如 SQL Server Entity ProviderTeradata 数据库官方提供了对 EntityFramework 的支持但可能是由于后来 EntityFramework 做了改动导致老的 Teradata Entity Provider 已经无法在 EntityFramework 6.1 上正常使用了Teradata 官方也没有及时更新 Provider。好了抛开任何杂念本着研究一下的态度试一下吧Teradata for .NET涉及到的 dllTeradata.Client.Provider.dllTeradata 数据库的底层驱动。此程序集采用强命名。并对下面的 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 得到 ILildasm Teradata.Client.Provider.dll /outputi.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.Cli65 6E 74 2E 45 6E 74 69 74 79 2C 20 50 75 62 6C // ent.Entity, Publ69 63 4B 65 79 3D 30 30 32 34 30 30 30 30 30 34 // icKey002400000438 30 30 30 30 30 39 34 30 30 30 30 30 30 30 36 // 800000940000000630 32 30 30 30 30 30 30 32 34 30 30 30 30 35 32 // 020000002400005235 33 34 31 33 31 30 30 30 34 30 30 30 30 30 31 // 534131000400000130 30 30 31 30 30 63 39 66 63 62 31 62 35 33 36 // 000100c9fcb1b53661 65 36 31 31 30 32 61 37 30 36 61 31 65 38 30 // ae61102a706a1e8031 65 36 32 65 64 34 37 35 39 32 37 39 36 34 35 // 1e62ed475927964537 65 30 36 33 36 39 61 63 61 63 31 34 62 65 66 // 7e06369acac14bef38 34 66 65 36 61 33 32 39 39 34 36 34 31 34 63 // 84fe6a329946414c39 65 30 35 65 32 65 62 66 65 64 66 30 36 61 66 // 9e05e2ebfedf06af33 66 39 36 32 37 36 64 34 32 31 35 32 38 30 37 // 3f96276d4215280736 39 35 37 63 35 30 32 33 35 63 36 65 38 31 37 // 6957c50235c6e81764 62 64 34 37 66 64 32 35 66 35 37 37 33 61 34 // dbd47fd25f5773a462 62 65 62 31 30 61 62 65 65 61 38 36 34 36 31 // bbeb10abeea8646133 34 33 34 66 34 39 63 38 36 30 63 35 34 32 38 // 3434f49c860c542831 31 66 36 35 61 30 38 35 65 35 33 34 65 65 34 // 11f65a085e534ee434 38 37 33 37 31 33 31 61 37 64 38 62 31 33 63 // 48737131a7d8b13c34 34 33 33 34 63 39 36 63 37 61 35 39 38 65 36 // 44334c96c7a598e665 65 36 38 65 63 61 66 64 34 66 37 63 61 31 33 // ee68ecafd4f7ca1338 37 33 33 38 37 35 34 64 65 61 38 65 36 33 30 // 87338754dea8e63031 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.Clie6E 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 编译为 DLLilasm.exe i.il /DLL /OUTPUTTeradata.Client.Provider.dll图 修改后这样 Teradata.Client.Entity.dll 就能编译通过了这还不算完还需要将 Teradata.Client.Entity.dll 里面的老的 EntityFramework Provider 实现修改为新实现基本上批量替换一下命名空间就可以了。