一次修改閉源 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”

運行項目。

 

最后,我認為比知道如何解決一個問題更重要的,是解決問題的思路,比思路更重要的,是遇到大大小小各種棘手、麻煩、混亂的問題時候仍然淡定的心態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM