如何解決本地DLL的PublicKeyToken與項目需要的DLL的PublicKeyToken不一致的問題


這個過程是這樣的。有一個遺留的項目需要做一些修改,那么我就從TFS上把這個項目下載下來,用VisualStudio打開。編譯時沒有發現錯誤,直接運行。可是運行時就拋出了異常。

Could not load file or assembly 'log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821' or one of its dependencies. 
The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)":"log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821"}

 

我的第一反應是這個Log4Net.dll找不到,覺得那么在reference列表中這個dll應該是黃色才對。右鍵查看項目引用的dll,發現 Log4Net.dll正常引用,並沒有黃色嘆號,說明找到了這個dll.(后來想想也對,如果有黃色嘆號標記的dll,那么說明找不到這個dll,那么 編譯的時候就應該報出異常,說找不到這個dll,所以由此總結,帶黃色嘆號的都是項目要用到的,但是沒有在本地找到的,編譯不會通過。如果沒有黃色嘆號拋 出上邊的異常,那么就是這個dll找到了,但是可能版本不一致。)

雙擊reference列表中的Log4Net.dll,可以看到其詳細的信息,可以看出,這個dll指向的路徑是GAC中,那么我就去GAC中找,確實在我本機找到了。

這個程序集存在於GAC中。那么我們查看一下這個Log4Net的dll信息。

果然,這里的publicKey Token與所需要的PublicKeyToken=1b44e1d426115821不一致。那么怎么解決這個問題?以前記得解決DLLversin不 一樣問題的時候,可以使用web.config或者app.config中的runtime節點進行redirect映射,那么 publicTokenKey 可以嗎?我找了找,沒有找到相關配置。怎么辦? 那么就去找指定publicKey token的dll吧。去哪里找?去Log4Net的官網找。確實,官網說明了它的dll變過publicKey token.

不過一般來講,一個公司發布產品類型的dll,本不應該變換publickey Token簽名的,否則會給用戶帶來像本文提到的這種問題,不同的人機器人可能安裝了不同publickeytoken的簽名版本,造成混亂。但是不知道 為什么Log4Net卻中途變了這個簽名,有newkey與oldkey版本。

我下載了new key的版本,覺得這個應該是項目需要的,但是怎么確定一下這個下載來的dll的publickkeytoken呢?這里就可以用VS自帶的工具。打開VS命令行,輸入sn命令就可以。

由此可以看到這個publickey token不是。所以繼續下載了oldkey的dll,使用同樣的方法,最終證實確實是需要oldkey的版本。所以,我下載下來這個 Log4Net.dll,然后在項目中建立一個Lib目錄,把dll放進去,讓項目對其添加引用。publickeyToken對了,此時我們需要看一 下,那么版本對嗎?右鍵查看這個新引用的dll的property,發現版本還真不對。項目需要Version=1.2.10.0,而這個新下載的是 1.2.13.0,那么怎么辦?這時就可以用版本映射來解決了。打開配置問題件,在節點中增加這些信息,意思就是需要1.2.10.0的時候,如果遇到了 1.2.13.0,那么就可以認為找到了對應的dll。

 

至此,編譯運行,發現問題解決,沒有再報任何的異常。

一些題外話:

以上的問題,都是由於項目開發時候的不規范造成的。像Log4Net這樣的非微軟集成到GAC中的dll,就應該在項目中建立一個Lib目錄存儲下 來,以后當有人下載代碼的時候,能夠連帶dll一起下載到本地,不用再大費周章的去找對應版本了。現在有時候是用Nuget就很好,那么額外的dll全會 放到package中,並且include到項目中。

 

還有關於dll version的映射問題,這個不是什么時候都OK的。

比如說,現在我用到了一個第三方的dll,叫做SuperLog.dll,這個dll是一個公司的產品,這個公司是引用 EntrepriseLogging.dll,引用的是5.0的版本,並且在這個基礎之上增加功能。我們在一個項目中用到了SuperLog.dll,我 們加入這個SuperLog.dll,編譯時告訴我們需要引入EntrepriseLogging.dll,但是我們手頭只有 EntrepriseLogging.dll6.0的版本。或許我們可以引入6.0的版本,但是重新映射到5.0版本。但是,我們這樣做了,編譯的時候還 是遇到了問題。異常好像是說,EntrepriseLogging沒有某個方法之類的。所以,這個意思就是說,以前5.0的時候,可能有一個方法A(), 正好被SuperLog調用了。但是在6.0版本的時候,EntrepriseLogging決定不要這個方法了。所以在我們項目中,雖然沒有拋出版本不 一樣的異常,但是當把6.0的版本當5.0的用,對這個6.0版本掉用A方法,但是沒有,就拋出了異常。

一般來講,第三方DLL發布新的版本,基本上不會更新對外暴露的方法,只是會更新方法中的內容。所以,不管哪個版本我們用到的都是同一個方法。但是 如果真的對外的方法都變了,增加了活減少了什么的,那么就會遇到上邊的問題。所以,不是所有的版本不同問題都能通過配置映射來解決。

 

為什么要有PublickKey Token?

其中一個很重要的原因就是安全角度考慮。這樣說吧,某公司開發了一個桌面程序A.exe,然后安裝包供下載。你下載完成,並且安裝。那么,在你的 ProgramFile里邊,就有A.exe與一些供其調用的dll,比如說B.dll,當你運行A的時候,會調用B.dll,完成相應操作。現在,如果 有某個非法程序偷偷的跑到A的目錄中,找到B.dll,然后把自己寫的同名的dll替換原來的。這時運行A的時候,調用B,就可能會有一些惡意非法操作。 PublicKey的作用之一就是用來驗證B是否是完全一致的B。驗證機制比較復雜,大家可以進一步探索。


免責聲明!

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



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