c#開發者在開發winform程式、asp.net web(mvc)程式等,不可避免的在專案中引用許多第三方的dll程式集,
編譯後引用的dll都放在根目錄下。以我個人作品
autoproject studio 自動化專案生成器為例,由於需要支援sql server、
oracle、mysql、postgresql、db2、sybase、infomix、sqlite、access等多種資料庫,
所以引用了dmprovider.dll、
ibm.data.db2.dll、ibm.data.informix.dll、mysql.data.dll、npgsql.dll、sqlite.interop.dll、
system.data.dll、
system.data.oracleclient.dll、sybase.adonet4.aseclient.dll 等dll,參考下圖:
隨著專案的日益增大,根目錄下充滿了各種各樣的dll,非常的不美觀。
如果能夠把dll按照想要的目錄來存放,那麼系統就美觀多了。
此問題就涉及到clr查詢和引導程式集的方式。
系統搜尋dll的目錄以及順序
clr解析乙個程式集會在乙個根目錄內進行搜尋,整個探索過程又稱probing,這個根目錄很顯然就是當前包含當前程式集的目錄。
程式搜尋dll的順序如下(區分強名稱簽名、沒有強名稱簽名的程式集)
沒有做強名稱簽名的程式集
程式的根目錄
根目錄下面,與被引用程式集同名的子目錄
根目錄下面被明確定義為私有目錄的子目錄
在目錄中查詢的時候,如果dll查詢不到,則會嘗試查詢同名的exe
如果程式集帶有區域性,而不是語言中立的,則還會嘗試查詢以語言區域命名的子目錄
強名稱簽名的程式集
全域性程式集快取
如果有定義codebase,則以codebase定義為準,如果 codebase指定的路徑找不到,則直接報告錯誤
程式的根目錄
根目錄下面,與被引用程式集同名的子目錄
根目錄下面被明確定義為私有目錄的子目錄
在目錄中查詢的時候,如果dll查詢不到,則會嘗試查詢同名的exe
如果程式集帶有區域性,而不是語言中立的,則還會嘗試查詢以語言區域命名的子目錄
如何讓程式識別不同目錄下的dll?
我們看到,上面的順序無論是否有強名稱簽名看,都提到了乙個名詞 「私有目錄」。
針對該問題,微軟提供了元素, 在配置檔案中自定義儲存目錄。
1上述 privatepath中的"bin;bin2\subbin;bin3",其中bin是預設編譯輸出目錄,bin2、bin3 是自定義目錄,subbin是bin2下的子目錄。<?xml version="
1.0" encoding="
utf-8
" ?>23
45"false
" />6"
urn:schemas-microsoft-com:asm.v1
">
7"bin;bin2\subbin;bin3
" />89
10
把dll分別放入上述目錄中,程式執行正常。
這是最簡單的方法,當然也有一定的侷限性,就是沒法對dll做控制。另外,無法解決第三方dllimport
中引入的程式集不在根目錄下的問題。
但是該方法基本解決了分目錄儲存的問題。
方法二:訂閱程式集解析事件 assemblyresolve 在**中解析
通過這個事件,我們可以在程式集解析時,根據不同的程式集做不用的處理,比如載入x86的程式集還是64位的程式集,當然也就可以指定程式集目錄了
這也正是 assembly.load 和 assembly.loadfrom 等方法的用武之地。
1方法三:using
system;
2using
system.io;
3using
system.reflection;
4using
system.windows.forms;56
namespace723
24///
25///
解析當前應用程式域內指定目錄下的dll
26///
27///
28///
29///
30private
static assembly currentdomain_assemblyresolve(object
sender,resolveeventargs args)
31.dll
",path);
35return
assembly.loadfrom(path);36}
37}38 }
1方法四:在載入使用到的dll**之前重置當前環境的目錄通過 environment.currentdirectory=custompath ,切換目錄後,在呼叫dll方法時執行正常。using
system;
2using
system.io;
3using
system.reflection;
4using
system.windows.forms;56
namespace723
2425
///26
///設定程式集所在的指定目錄並解析dll
27///
28private
static
void
setprivatebinpath()
29.config"39
",null
,setup);
41int ret =newdomain.executeassemblybyname(currentassembly.fullname);
4243
44 environment.exitcode =ret;
45 environment.exit(0
);46
return;47
}48}49
}50 }
處理 [dllimport] 中的程式集的載入,此處提供用一種方式來處理:增加環境變數。
c#**如下:
staticvoid addenvironmentpaths(ienumerablepaths)
;
string newpath = string
.join(path.pathseparator.tostring(), path.concat(paths));
environment.setenvironmentvariable(
"path
", newpath);
}
CLR 程式集和命名空間
控制台應用program並非只是含有元資料的pe檔案,他還是程式集 assembly 程式集是乙個或多個型別定義檔案及資源檔案的集合。在程式及的所有檔案中,有乙個檔案容納了清單 manifest 清單也是乙個元資料表集合,表中主要包含作為程式集組成部分的那些檔案的名稱。此外,還描述了程式集的版本 語...
CLR 共享程式集和強命名程式集
2017年08月12日 23 36 52 生活常識 閱讀數 187 clr支援兩種型別的程式集 弱命名程式集 weakly named assembly 和強命名程式集 strongly named assembly 二者的區別 強命名程式集使用發布者的公鑰 私鑰進行了簽名。這一堆金鑰允許對程式集進...
C 如何引導程式執行目錄外的程式集
我們的應用程式部署的時候,目錄結構一般不會只有執行程式的目錄這乙個,我們可能在執行目錄下建子目錄,也可能使用system32目錄,也可能使用其它第三方的程式集。net程式集 首先會在gac中搜尋相應的版本,如果未找到則會應用程式配置檔案中找 如果配置 最後到應用程式所在的路徑搜尋。configura...