.NET分離exe和dll在不同的目錄讓你的程序更整潔
1、引言
在一個(gè)項(xiàng)目開發(fā)中一般都是把引用的dll放在根目錄下,隨著項(xiàng)目的日益增大,根目錄下的dll文件就會(huì)越來越多,合理規(guī)劃這些dll的存放地址,可以使整個(gè)項(xiàng)目更加的規(guī)范與美觀。這篇文章就為大家介紹關(guān)于C#如何在指定文件夾尋找文件dll的相關(guān)內(nèi)容,文中通過基于RDIFramework框架WinForm版為基礎(chǔ)進(jìn)行介紹,Web的相關(guān)dll規(guī)劃類似,希望對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值。
我們框架原執(zhí)行目錄下的dll存放如下,可以看到整個(gè)目錄下的文件非常多。

下面我們通過最常用的方式對(duì)dll文件進(jìn)行規(guī)劃處理,使整個(gè)運(yùn)行目錄更加的干凈,規(guī)范,最終效果如下圖所示。

可以看到,上圖的整個(gè)運(yùn)行目錄結(jié)構(gòu)非常的清爽與整潔了。如何實(shí)現(xiàn)的呢?下面我們就具體講解。
2、實(shí)現(xiàn)方法
2.1、系統(tǒng)搜索dll的目錄以及順序
CLR解析一個(gè)程序集會(huì)在一個(gè)根目錄內(nèi)進(jìn)行搜索,整個(gè)探索過程又稱Probing,這個(gè)根目錄很顯然就是當(dāng)前包含當(dāng)前程序集的目錄。
AppDomainSetup這個(gè)類存儲(chǔ)著探索目錄的信息,其成員包括:ApplicationBase、PrivateBinPath。
程序搜索dll的順序如下(區(qū)分強(qiáng)名稱簽名的和沒有強(qiáng)名稱簽名的程序集):
沒有做強(qiáng)名稱簽名的程序集:
- 程序的根目錄
- 根目錄下面,與被引用程序集同名的子目錄
- 根目錄下面被明確定義為私有目錄的子目錄
- 在目錄中查找的時(shí)候,如果dll查找不到,則會(huì)嘗試查找同名的exe
- 如果程序集帶有區(qū)域性,而不是語言中立的,則還會(huì)嘗試查找以語言區(qū)域命名的子目錄
具有強(qiáng)名稱簽名的程序集:
全局程序集緩存
如果有定義codebase,則以codebase定義為準(zhǔn),如果codebase指定的路徑找不到,則直接報(bào)告錯(cuò)誤
程序的根目錄
根目錄下面,與被引用程序集同名的子目錄
根目錄下面被明確定義為私有目錄的子目錄
在目錄中查找的時(shí)候,如果dll查找不到,則會(huì)嘗試查找同名的exe
如果程序集帶有區(qū)域性,而不是語言中立的,則還會(huì)嘗試查找以語言區(qū)域命名的子目錄。如下圖所示:

2.2、如何讓程序識(shí)別不同目錄下的dll?
我們看到,上面的順序無論是否有強(qiáng)名稱簽名,都會(huì)用到私有目錄,要實(shí)現(xiàn)程序識(shí)別不同目錄下的dll文件,一般有三種方式。
1、配置App.config文件的privatePath——【推薦】。
2、訂閱程序集解析事件AssemblyResolve在代碼中解析。
3、在加載使用到dll的代碼之前重置當(dāng)前環(huán)境的目錄。
2.2.1、配置App.config文件的privatePath——【推薦】
這是最簡單最常用的方法,也是我們采用的方式。這兒要說明的是此方法有一定的局限性,就是沒法對(duì)dll做控制,另外無法解決第三方DllImprt中引入的程序集不在根目錄下的問題。配置如下,多個(gè)目錄用;分隔。
<configuration>
<runtime>
<!--xmlns是必需的特性。指定程序集綁定所需的 XML 命名空間。 使用字符串“urn: 架構(gòu)-microsoft-com:asm.v1”作為值。-->
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<publisherPolicy apply="yes"/> <!--指定運(yùn)行時(shí)是否使用發(fā)布者策略-->
<!--指定加載程序集時(shí)公共語言運(yùn)行時(shí)搜索的子目錄, 其中privatePath是相對(duì)于*.exe.config文件的相對(duì)路徑,多個(gè)文件夾以分號(hào)分隔。-->
<probing privatePath="devLibs;3rdLibs;frameworkLibs"/>
</assemblyBinding>
</runtime>
</configuration>
其中privatePath是相對(duì)于*.exe.config文件的相對(duì)路徑,多個(gè)文件夾以分號(hào)分隔。當(dāng)編譯后會(huì)在生成目錄下生成一個(gè)后綴為.exe.config的文件,就是相對(duì)這個(gè)文件的。
添加程序集DLL引用之后,將DLL的屬性“復(fù)制本地”設(shè)置為False。程序編譯過程中,會(huì)自動(dòng)檢索Common和Security文件夾下的DLL及其依賴項(xiàng)。
我們框架就是使用這種方式來實(shí)現(xiàn),最終的運(yùn)行目錄結(jié)構(gòu)效果如下。

2.2.2、訂閱程序集解析事件AssemblyResolve在代碼中解析。
應(yīng)用程序集域中支持在程序集解析時(shí)的處理:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
通過這個(gè)事件,我們可以在程序集解析時(shí),根據(jù)不同的程序集做不用的處理,比如加載x86的程序集還是64位的程序集,當(dāng)然也就可以指定程序集目錄了。這也正是Assembly.Load和Assembly.LoadFrom等方法的用武之地。
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AssemblyName assemblyName = new AssemblyName(args.Name);
return Assembly.LoadFrom(Path.Combine(baseDirectory, "3rdLibs"));
}
2.2.3、在加載使用到dll的代碼之前重置當(dāng)前環(huán)境的目錄。
這個(gè)方法是通過Environment.CurrentDirectory=customPath,這樣在調(diào)用dll方法時(shí),因?yàn)槟夸浺呀?jīng)切換到了我們指定的目錄下,就可以實(shí)現(xiàn)相應(yīng)的dll正確的加載。這是一個(gè)取巧的方法不是很實(shí)用,需要來回切換程序集目錄,但是在某些情況下非常好用。
2.3、如何處理[dllImport]中的程序集的加載
針對(duì)dllImport也分為幾種情況。
自己寫
dllImport引用的C#的插件又使用了
dllImport
2.3.1、自己寫的dllImport
如果是自己寫的就非常好控制了,可以直接指定相對(duì)的目錄DllImport(3rdLibs\NLog.dll)。不過這種方法不一定可靠,在某些系統(tǒng)加載不了,如果使用了dllImport還是,推薦下面的介紹的方法(引用的C#的插件又使用了dllImport)。
2.3.2、引用的C#的插件又使用了dllImport
因?yàn)闊o法更改路徑,那么只能夠使用上述特殊的方法,更改當(dāng)前程序的路徑
當(dāng)然,還有更省事一點(diǎn)的做法,就是在系統(tǒng)環(huán)境中,增加一條記錄,指向要加載的dll的所在目錄。因?yàn)镃++的代碼中,Windows目錄和Windows\System32目錄以及環(huán)境變量設(shè)定的目錄都是搜索路徑之一。
這里提供怎么從C#中修改系統(tǒng)環(huán)境變量的代碼:
static void AddEnvironmentPaths(IEnumerable<string> paths)
{
var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty };
string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths));
Environment.SetEnvironmentVariable("PATH", newPath);
}
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值。
3、運(yùn)行效果


4、參考文章
4.1、文章相關(guān)
4.2、框架相關(guān)
最好用的.NET敏捷開發(fā)框架-RDIFramework.NET V3.6版全新發(fā)布 100%源碼授權(quán)
RDIFramework.NET — 基于.NET的快速信息化系統(tǒng)開發(fā)框架 — 系列目錄
RDIFramework.NET敏捷開發(fā)框架 ━ 工作流程組件介紹
RDIFramework.NET框架SOA解決方案(集Windows服務(wù)、WinForm形式與IIS形式發(fā)布)-分布式應(yīng)用
微信公眾號(hào)開發(fā)系列-玩轉(zhuǎn)微信開發(fā)-目錄匯總
RDIFramework.NET敏捷開發(fā)框架 ━ 工作流程組件Web業(yè)務(wù)平臺(tái)
RDIFramework.NET敏捷開發(fā)框架通過SignalR技術(shù)整合即時(shí)通訊(IM)
RDIFramework.NET框架基于Quartz.Net實(shí)現(xiàn)任務(wù)調(diào)度詳解及效果展示
RDIFramework框架整合微信開發(fā)應(yīng)用效果展示
一路走來數(shù)個(gè)年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址了解詳情。
RDIFramework.NET官方網(wǎng)站:http://www.rdiframework.net/
RDIFramework.NET官方博客:http://blog.rdiframework.net/
同時(shí)需要說明的,以后的所有技術(shù)文章以官方網(wǎng)站為準(zhǔn),歡迎大家收藏!
RDIFramework.NET框架由海南國思軟件科技有限公司專業(yè)團(tuán)隊(duì)長期打造、一直在更新、一直在升級(jí),請(qǐng)放心使用!
歡迎關(guān)注RDIFramework.net框架官方公眾微信(微信號(hào):guosisoft),及時(shí)了解最新動(dòng)態(tài)。
掃描二維碼立即關(guān)注

作者:
RDIF
出處:
http://www.rzrgm.cn/huyong/
Email:
406590790@qq.com
QQ:
406590790
微信:
13005007127(同手機(jī)號(hào))
框架官網(wǎng):
http://www.guosisoft.com/
http://www.rdiframework.net/
框架其他博客:
http://blog.csdn.net/chinahuyong
http://www.rzrgm.cn/huyong
國思RDIF開發(fā)框架
,
給用戶和開發(fā)者最佳的.Net框架平臺(tái)方案,為企業(yè)快速構(gòu)建跨平臺(tái)、企業(yè)級(jí)的應(yīng)用提供強(qiáng)大支持。
關(guān)于作者:系統(tǒng)架構(gòu)師、信息系統(tǒng)項(xiàng)目管理師、DBA。專注于微軟平臺(tái)項(xiàng)目架構(gòu)、管理和企業(yè)解決方案,多年項(xiàng)目開發(fā)與管理經(jīng)驗(yàn),曾多次組織并開發(fā)多個(gè)大型項(xiàng)目,在面向?qū)ο蟆⒚嫦蚍?wù)以及數(shù)據(jù)庫領(lǐng)域有一定的造詣。現(xiàn)主要從事基于
RDIF
框架的技術(shù)開發(fā)、咨詢工作,主要服務(wù)于金融、醫(yī)療衛(wèi)生、鐵路、電信、物流、物聯(lián)網(wǎng)、制造、零售等行業(yè)。
如有問題或建議,請(qǐng)多多賜教!
本文版權(quán)歸作者和CNBLOGS博客共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,如有問題,可以通過微信、郵箱、QQ等聯(lián)系我,非常感謝。

浙公網(wǎng)安備 33010602011771號(hào)