當我們要建立一個隨插 (DLL) 即用 (Method) 的系統的時候,我們會使用類別函式庫專案來建置 DLL,但預設建置類別函式庫專案只會輸出你所寫的程式(通常只有一隻 DLL),不會包含額外參考的 DLL 函示庫檔案(例如 NuGet 的套件),這時會造成一些小困擾,我們可以怎樣優雅的處理這個問題呢?
撰寫類別函式庫專案建議使用 .NET Standard 來做,讓之後跨平台時能輕鬆銜接。這裡的平台指的是 .NET Framework、.NET Core、Xamarin 等 .NET 家族的平台實作(參考這裡)。
情境
假設我們有個 Plug-in System,根據需要動態載入 DLL,當我們要新增加功能時,只要把包含新功能的 DLL 複製至指定的資料夾位置即可,系統會利用 .NET 的反射機制(System.Reflection)來調用新功能。
這時如果你使用類別函式庫專案寫好新功能,而這個專案裡面安裝了許多 NuGet 套件,建置的時候你會發現輸出的檔案只有少少的三個(如下圖)。
那些我們安裝的 NuGet 套件所提供的 DLL 檔案,都不會出現在這個資料夾中,他們會被記錄在 .deps.json
檔案中,這個產生的 JSON 檔案 (*.deps.json) 會列出你的應用程式所相依的套件及 runtime 環境。
在這樣的情況下,如果我們將此輸出的 DLL 複製至我們的 Plug-in System,有時候是可以正常運作的。
為什麼是有時候呢?要正常運作的前提是,這個 Plug-in System 本身有提供這個 DLL 所相依的所有套件,套件的版本也要正確,才能正確運行;如果有缺,那就需要在 Plug-in System 中,先把所需要的套件安裝上去。
這樣其實不是很方便,因為既然是 Plug-in System,就希望不要變動系統底層的東西,把變動封鎖在 Plug-in 本身才是最方便的。
作法
要做到將類別函式庫專案中所參考的 DLL 函示庫跟著建置做輸出,只需要一個設定。
透過修改 .csproj
專案檔,在 <PropertyGroup>
屬性中加入一行設定 <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
,完整程式碼如下:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>
</Project>
在範例專案我加入的兩個 NuGet 套件:Dapper 和 Newtonsoft.Json,而在修改設定並執行建置後,你會發現輸出資料夾中會多很多檔案(如下圖):
多出來的檔案可以分成兩種,一種是 NuGet 套件本身的 DLL,另一種是 NuGet 套件相依的 DLL,例如 Newtonsoft.Json 套件就會多出一個 Newtonsoft.Json.dll
,而 Dapper 套件除了會多出一個 Dapper.dll
外,還會出現其他相依的 DLL 檔。
如此一來我們就可以強制專案在建置時,將相依的套件整個複製至輸出資料夾了。
參考資料: