團隊開發要共享 .NET 元件,一個標準的方式就把類別庫專案打包成 NuGet 套件,再發佈到公開 nuget.org 或內部私有 NuGet 伺服器甚至簡單的放到共用資料夾,開發人員即可透過 NuGet 取用。

前一篇 由類別庫建立 NuGet 套件 介紹了建立單一專案套件的基本步驟。

本篇針對實務上常見的多專案打包的情況做記錄。

建立範例類別庫

延續第一篇的範例方案,加入第二個專案。

範例方案中加入第二個專案

  1. 加入一個新的類別庫專案,取名 NetReader。
  2. 專案中新增類別: WebPageReader.cs
  3. 程式內容:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    namespace NetReader
    {
    public class WebPageReader
    {
    public static string Fetch(string url)
    {
    return "<div></div>";
    }
    }
    }

只回固定的資料,沒真的用 HttpClient 取值。

這樣方案裡有2個專案:

1
2
3
4
5
HtmlParser
> HtmlParser
> NodeReader.cs
> NetReader
> WebPageReader.cs

同方案的專案參考

在 HtmlParser 中加入對 NetReader 的參考。

打包時加入參考的專案

在參考了 NetReader 後,對 HtmlParser 用 nuget pack 命令做打包,解開 .nupkg 來看裡面的 lib 目錄及 HtmlParser.nuspec 檔案內容,可以發現並沒有加入 NetReader 的任何相關內容。

如果用戶專案從 Server 上安裝了這個套件,將會有參考不到 NetReader 的錯誤。

1
未處理的例外狀況: System.IO.FileNotFoundException: 無法載入檔案或組件 'NetReader, ...'

自動加入參考專案

打包命令
nuget pack {project_file} -IncludeReferencedProjects

加上 -IncludeReferencedProjects 後,nuget 會針對方案中被參考到的專案做查找,如果該專案是 nuget 套件 (有 .nuspec 檔),那麼專案套件資訊就會被加入到套件檔中 xxx.nuspec 裡的 dependencies 設定值,安裝時就一併從套件庫做安裝。

而那些不是 nuget 套件 (沒有 .nuspec 檔) 的專案,它們的 DLL 就會被包進套件的 lib 目錄下,在安裝時一併加入。

在有 NetReader.nuspec 時,HtmlParser.nuspec 如下例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>HtmlParser</id>
<version>1.0.0.7</version>
<title>HtmlParser title</title>
<authors>demo</authors>
<owners>demo</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>demo</description>
<copyright>Copyright 2018</copyright>
<dependencies>
<dependency id="HtmlAgilityPack" version="1.8.4" />
<dependency id="NetReader" version="1.0.0.2" />
</dependencies>
</metadata>
</package>

這個情境下,要確認 NetReader 套件已發佈到 NuGet Server,不然用戶在安裝 HtmlParser 時,找不到 NetReader 套件,就會發生 “無法解析相依性” 錯誤,如下:

1
無法解析相依性 'NetReader'。已使用來源: 'nuget.org', 'private source'...

套件包含 Solution 中的多個專案

有些時候,是整個 Solution 或一部份專案合作提供了一組服務,這時候就可以把相關的 DLLs 都打包在一起成為套件以方便被使用。

準備 .nuspec

在方案目錄下,執行 nuget spec 命令建立 .nuspec 檔。

這時因為沒有專案資訊可參考,檔案名稱統一叫 Package.nuspec,內容也都是樣版內容,名稱及內容要自行依套件性質做修改。

加入套件參考 dependencies

產生的 nuspec 中已包含 dependencies 的範例,要依實際上有沒有參考到其它套件來做修改或刪除它。

在範例方案中,可以加上對 HtmlAgilityPack 的參考,像是:
<dependency id="HtmlAgilityPack" version="1.8.4" />

加入檔案

用 files 區段來把檔案加入套件中,主要就是各專案的 DLL 檔也可加入 .pdb 檔,其它必要的各式檔案也都可以加入。

平行 metadata 下加入 <files></files> 區段,當中利用 <file src=".." target=".." /> 來指定一個檔案單元:

  • src -
    指定要打包進來的來源檔案。
  • target -
    指定輸出 .NET Framework 版本路徑,不支援多版本時,可保留 “ “。

範例看起來如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<package >
<metadata>
<id>PowerHtmlParser</id>
<version>1.0.0</version>
<title>HtmlParser</title>
<authors>demo</authors>
<owners>demo</owners>
<description>NuGet pack demo</description>
<copyright>Copyright 2018</copyright>
<dependencies>
<dependency id="HtmlAgilityPack" version="1.8.4" />
</dependencies>
</metadata>
<files>
<file src="HtmlParser\bin\Debug\*.dll" target="lib\net471" />
<file src="NetReader\bin\Debug\*.dll" target="lib\net471" />
</files>
</package>

建立套件時,nuget pack 命令會使用專案檔的設定值或 pack 命令的 -properties 參數值,來取代 .nuspec 檔案之 \ 節點的 \$xxxx$ token 值。如:

nuget pack MyProject.csproj -properties owners=john

除了前一篇提到的 \$id$ \$version$ … 等,還可以利用 \$configuration$ token 值來動態取得組建組態值,在 pack 時就可使用 -properties Configuration=Release
來指定 Release 組態。用法如下:

1
2
3
<files>
<file src="NetReader\bin\$configuration$\*.dll" target="lib\net45" />
</files>

nuspec 調整完後,執行 nuget pack 即可進行打包。

參考資料及圖片來源

  1. 官方-套件建立工作流程
  2. 官方- .nuspec 參考