.NET分離exe和dll在不同的目錄讓你的程序更整潔

1、引言

在一個項目開發中一般都是把引用的dll放在根目錄下,隨着項目的日益增大,根目錄下的dll文件就會越來越多,合理規劃這些dll的存放地址,可以使整個項目更加的規範與美觀。這篇文章就爲大家介紹關於C#如何在指定文件夾尋找文件dll的相關內容,文中通過基於RDIFramework框架WinForm版爲基礎進行介紹,Web的相關dll規劃類似,希望對大傢俱有一定的參考學習價值。

我們框架原執行目錄下的dll存放如下,可以看到整個目錄下的文件非常多。
原框架運行目錄結構

下面我們通過最常用的方式對dll文件進行規劃處理,使整個運行目錄更加的乾淨,規範,最終效果如下圖所示。
框架運行目錄規劃後的結構

可以看到,上圖的整個運行目錄結構非常的清爽與整潔了。如何實現的呢?下面我們就具體講解。

2、實現方法

2.1、系統搜索dll的目錄以及順序

CLR解析一個程序集會在一個根目錄內進行搜索,整個探索過程又稱Probing,這個根目錄很顯然就是當前包含當前程序集的目錄。
AppDomainSetup這個類存儲着探索目錄的信息,其成員包括:ApplicationBase、PrivateBinPath。
程序搜索dll的順序如下(區分強名稱簽名的和沒有強名稱簽名的程序集):
沒有做強名稱簽名的程序集:

  1. 程序的根目錄
  2. 根目錄下面,與被引用程序集同名的子目錄
  3. 根目錄下面被明確定義爲私有目錄的子目錄
  4. 在目錄中查找的時候,如果dll查找不到,則會嘗試查找同名的exe
  5. 如果程序集帶有區域性,而不是語言中立的,則還會嘗試查找以語言區域命名的子目錄

具有強名稱簽名的程序集:

  1. 全局程序集緩存

  2. 如果有定義codebase,則以codebase定義爲準,如果codebase指定的路徑找不到,則直接報告錯誤

  3. 程序的根目錄

  4. 根目錄下面,與被引用程序集同名的子目錄

  5. 根目錄下面被明確定義爲私有目錄的子目錄

  6. 在目錄中查找的時候,如果dll查找不到,則會嘗試查找同名的exe

  7. 如果程序集帶有區域性,而不是語言中立的,則還會嘗試查找以語言區域命名的子目錄。如下圖所示:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uFmauJ8N-1587204888235)(http://doc.rdiframework.net/blog/article/20200418180408778.png-pw)]

2.2、如何讓程序識別不同目錄下的dll?

我們看到,上面的順序無論是否有強名稱簽名,都會用到私有目錄,要實現程序識別不同目錄下的dll文件,一般有三種方式。

1、配置App.config文件的privatePath——【推薦】。

2、訂閱程序集解析事件AssemblyResolve在代碼中解析。

3、在加載使用到dll的代碼之前重置當前環境的目錄。

2.2.1、配置App.config文件的privatePath——【推薦】

這是最簡單最常用的方法,也是我們採用的方式。這兒要說明的是此方法有一定的侷限性,就是沒法對dll做控制,另外無法解決第三方DllImprt中引入的程序集不在根目錄下的問題。配置如下,多個目錄用;分隔。

<configuration>
<runtime>
      <!--xmlns是必需的特性。指定程序集綁定所需的 XML 命名空間。 使用字符串“urn: 架構-microsoft-com:asm.v1”作爲值。-->
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <publisherPolicy apply="yes"/>  <!--指定運行時是否使用發佈者策略-->
        <!--指定加載程序集時公共語言運行時搜索的子目錄, 其中privatePath是相對於*.exe.config文件的相對路徑,多個文件夾以分號分隔。-->
        <probing privatePath="devLibs;3rdLibs;frameworkLibs"/>
    </assemblyBinding>
  </runtime>
</configuration>

其中privatePath是相對於*.exe.config文件的相對路徑,多個文件夾以分號分隔。當編譯後會在生成目錄下生成一個後綴爲.exe.config的文件,就是相對這個文件的。
添加程序集DLL引用之後,將DLL的屬性“複製本地”設置爲False。程序編譯過程中,會自動檢索Common和Security文件夾下的DLL及其依賴項。

我們框架就是使用這種方式來實現,最終的運行目錄結構效果如下。
框架運行目錄規劃後的結構

2.2.2、訂閱程序集解析事件AssemblyResolve在代碼中解析。

應用程序集域中支持在程序集解析時的處理:

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

通過這個事件,我們可以在程序集解析時,根據不同的程序集做不用的處理,比如加載x86的程序集還是64位的程序集,當然也就可以指定程序集目錄了。這也正是Assembly.LoadAssembly.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的代碼之前重置當前環境的目錄。

這個方法是通過Environment.CurrentDirectory=customPath,這樣在調用dll方法時,因爲目錄已經切換到了我們指定的目錄下,就可以實現相應的dll正確的加載。這是一個取巧的方法不是很實用,需要來回切換程序集目錄,但是在某些情況下非常好用。

2.3、如何處理[dllImport]中的程序集的加載

針對dllImport也分爲幾種情況。

自己寫dllImport

引用的C#的插件又使用了dllImport

2.3.1、自己寫的dllImport

如果是自己寫的就非常好控制了,可以直接指定相對的目錄DllImport(3rdLibs\NLog.dll)。不過這種方法不一定可靠,在某些系統加載不了,如果使用了dllImport還是,推薦下面的介紹的方法(引用的C#的插件又使用了dllImport)。

2.3.2、引用的C#的插件又使用了dllImport

因爲無法更改路徑,那麼只能夠使用上述特殊的方法,更改當前程序的路徑
當然,還有更省事一點的做法,就是在系統環境中,增加一條記錄,指向要加載的dll的所在目錄。因爲C++的代碼中,Windows目錄和Windows\System32目錄以及環境變量設定的目錄都是搜索路徑之一。
這裏提供怎麼從C#中修改系統環境變量的代碼:

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);
}

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值。

3、運行效果

框架運行效果1
框架運行效果2

4、參考文章

4.1、文章相關

4.2、框架相關

最好用的.NET敏捷開發框架-RDIFramework.NET V3.6版全新發布 100%源碼授權

RDIFramework.NET — 基於.NET的快速信息化系統開發框架 — 系列目錄

RDIFramework.NET敏捷開發框架 ━ 工作流程組件介紹

RDIFramework.NET框架SOA解決方案(集Windows服務、WinForm形式與IIS形式發佈)-分佈式應用

微信公衆號開發系列-玩轉微信開發-目錄彙總

史上最全面的SignalR系列教程-目錄彙總

RDIFramework.NET敏捷開發框架 ━ 工作流程組件Web業務平臺

RDIFramework.NET敏捷開發框架通過SignalR技術整合即時通訊(IM)

RDIFramework.NET框架基於Quartz.Net實現任務調度詳解及效果展示

RDIFramework框架整合微信開發應用效果展示


一路走來數個年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址瞭解詳情。

RDIFramework.NET官方網站:http://www.rdiframework.net/

RDIFramework.NET官方博客:http://blog.rdiframework.net/

同時需要說明的,以後的所有技術文章以官方網站爲準,歡迎大家收藏!

RDIFramework.NET框架由海南國思軟件科技有限公司專業團隊長期打造、一直在更新、一直在升級,請放心使用!

歡迎關注RDIFramework.net框架官方公衆微信(微信號:guosisoft),及時瞭解最新動態。

掃描二維碼立即關注

微信號:guosisoft

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章