建立並發布你的 NuGet 套件

摘要:這篇筆記包含建立與發布 NuGet 套件的基礎操作。

如果你也想試試把自己的類別庫打包成 NuGet 套件 (package; 封裝),並發布至 nuget.org 伺服器,讓別人可以在 NuGet Gallery 上找到並下載你寫的元件,這篇筆記應該可以減少一些自行摸索的時間。

Step 0:準備工作

當我們說「建立與發佈 NuGet 套件」時,實際涉及的主要操作的確就只有兩個:「建立套件」和「發布套件」。前者對應的 NuGet 命令列指令是 nuget pack,後者則是 nuget push

在此之前,有個事前準備工作得先完成:
  • NuGet 官網註冊一個帳號。註冊完成後,進入你的 NuGet 帳戶頁面,會看到此帳戶專屬的 API Key。將來發布你的 NuGet 套件時會用到這個 key。
此動作只須執行一次。往後每次要發布新的 NuGet 套件時,照底下步驟進行即可。

Step 1:建立 .nuspec 檔案

建立 NuGet 套件(打包)的動作需要你提供一個 XML 格式的設定檔,這個檔案的副檔名是 .nuspec。如果你已經很熟悉 nuspec 檔案的用法,大可選擇你認為最方便的方式來產生這個檔案。這裡示範的方法是先利用工具來產生這個檔案,並以此為範本來進一步修改成我們需要的內容。

假設你已經有一個 Visual Studio Solution 檔案,其中包含一些 .csproj(或 .vbproj)類別庫專案。寫這篇文章時,我的範例專案的整個目錄結構大概像這樣:

+ Solution Root Folder\
  + Build\
    + Debug\
      - *.DLL files
    + Release\
      *.DLL files
  + Source\
    HuanlinToolkit.sln
    + Hlt.Core\
      Hlt.Core.csproj    
      *.cs files
    + Hlt.Data\
      Hlt.Data.csproj
    + Hlt.Web\
      Hlt.Web.csproj

我是把每個 .csproj 專案的輸出路徑指到上一層的 Build 資料夾下的 Debug 或 Release(視建置組態而定),而不是預設的 bin\Debug | Release。因此,後續步驟中涉及資料夾路徑的操作時,都是以此目錄結構為前提。如果你的專案目錄結構並非如此安排,請自行修改相關路徑。

在 Visual Studio 裡面開啟這個 Solution,於 Solution Explorer 中,方案名稱上面點滑鼠右鍵,選擇 Enable NuGet Package Restore,如下圖:

此動作完成後,在此方案的根目錄下會產生一個名為 .nuget 的子目錄,裡面會有一個 NuGet.exe。此動作的目的只在於取得 NuGet.exe 這個命令列工具。
Note:你可能會比較喜歡另一種方式:自行下載 NuGet 命令列工具,然後把 NuGet.exe 放在某個專門存放工具的目錄下,並將此目錄加入環境變數 PATH 中,以便在任何地方都能執行。

接著開啟 Windows 的命令列視窗(命令提示字元),將現行目錄切換到你的 .NET Solution 底下的任意一個專案目錄,例如 MyLib.Core\ 目錄(此目錄下會有 MyLib.Core.csproj 專案檔),然後輸入以下命令:

..\.nuget\NuGet.exe pack

此命令會為現行目錄下的 .csproj 專案產生一個打包好的 .nupkg 檔案。執行過程如下圖:


這個 .nupkg 其實是個 zip 壓縮檔。把它解壓縮到任意一個暫存目錄下,你會看到一個副檔名為 .nuspec 的檔案。我們會以這個檔案作為基礎範本來建立自己的套件設定檔。

以剛才的螢幕截圖為例,我的範例專案名稱是 Hlt.Data,而上述步驟所產生的套件檔案名稱是 Hlt.Data.1.0.0.0.nupkg。將此套件檔案解壓縮,裡面有個 Hlt.Data.nuspec。
註:這版本號碼的格式不大好。我後來已經改用 MAJOR.MINOR.PATCH 格式了,也就是版號只包含三個部分,例如 1.4.0。 

如果只想要單純把一個 DLL 組件打包成 NuGet 套件,上述步驟基本上已經算是完成了。不過,我要發布的 NuGet 套件裡面並不只 Hlt.Data.DLL;我想要把整個 Solution 方案裡面包含的多個 .csproj 所產生的 DLL 組件都打包成一個 NuGet 套件。所以我是把這個 Hlt.Data.nuspec 檔案複製到專案目錄結構中的 Build 資料夾下(參考前面的專案目錄結構),並改名為 Hlt.nuspec。

接著用文字編輯器修改 Hlt.nuspec。參考以下範例:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>HLT</id>
    <version>0.0.0</version>
    <title>HLT Library</title>
    <authors>Huanlin Tsai</authors>
    <owners>Huanlin Tsai</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>.NET Utility Library</description>
    <copyright>Copyright© 2014 Huanlin Tsai</copyright>
    <dependencies />
  </metadata>
  <files>
    <file src="Debug\*.dll" target="lib\net40" />
  </files>
</package>

其中除了 <files> 區段需要額外加入,其餘元素應該都已經由工具自動產生了,只需修改元素值即可。

<files> 區段中的每個元素即代表一個要包進套件的檔案,src 屬性指定檔案的來源路徑名稱,target 屬性則指定其目標檔名,亦即打包到套件裡面的目標資料夾和檔案名稱。

注意 <version> 元素值是 "0.0.0",這是因為我打算等到使用命令列工具來建立套件時才由命令列參數傳入。

Step 2:建立 .nupkg 檔案(打包)

準備好 .nuspec 檔案之後,接下來的打包動作就簡單多了。作法是開啟命令列視窗,切換到 .nuspec 檔案所在的目錄,然後輸入以下命令:

..\Source\.nuget\NuGet.exe pack HLT.nuspec -Version 1.4.0

按照上一個步驟建立的 HLT.nuspec 檔案,此命令會產生一個名為 HLT.1.4.0.nupkg 的檔案。你可以把這個檔案解壓縮來看看裡面有哪些東西,然後對照一下 .nuspec 檔案中的 <files> 區段,以了解其對應關係。

Step 3:發布至 NuGet.org

一旦建立好 .nupkg 檔案,剩下的動作就是發佈至 NuGet 伺服器了。

發布套件時,會需要你的 NuGet API Key。這 API Key 字串內容挺長的,不太可能記得起來,而每次要用的時候還得找出來複製貼上,也有點麻煩。方便起見,我們可以先把自己的 NuGet 帳戶的專屬 API Key 保存在本機電腦,就好像記住網站的會員密碼,只需輸入一次。

在本機保存 API Key 的作法是開啟命令列視窗,切換到 NuGet.exe 所在目錄,然後輸入以下命令:

NuGet.exe SetApiKey {你的 API Key}

{你的 API Key} 可以從你的 NuGet 帳戶頁面找到。

設定完成後,你的 API Key 就會保存在這台電腦的這個檔案裡:

c:\Users\{帳戶名稱}\AppData\Roaming\NuGet\NuGet.Config

檔案內容不太重要,就不列出來了。

一旦 API Key 設置完成,以後要發布你的 NuGet 套件時,只要開啟命令列視窗,切到 .nuspec 檔案所在目錄,然後輸入以下命令,便可將指定的 .nupkg 檔案推送至 NuGet.org 伺服器:

NuGet.exe push {你的 .nupkg 檔案}

按先前的範例,實際輸入的命令會像這樣:

..\Source\.nuget\NuGet.exe push HLT.1.4.0.nupkg

推送檔案完成後,到 NuGet.org 登入你的帳戶,便可線上管理自己的套件,如下圖:


從這張截圖可以發現,網站亦提供上傳套件的功能(左邊的 Upload a Package 連結)。若不喜歡使用命令列工具,這也是另一個選擇。

點擊 Manage my Packages 連結便可以看到你曾經推送至 NuGet.org 的套件:


另外,在 Visual Studio 中使用 NuGet Package Manager 來管理專案所參考的組件時也能搜尋到自己發布的套件(在 NuGet 網站上輸入關鍵字搜尋當然也能找到):


其他操作:更新版本、移除套件

套件一旦發布至 NuGet.org 伺服器,同一個版本就不能重複發布(NuGet 會報錯),亦即不能覆蓋先前發布至伺服器的套件。如欲發布新版本,必須打包成不同版本號碼的套件才能夠發布。

此外,NuGet 雖然有提供 Delete 指令,但實際上並不會真的從伺服器上刪除套件,而只是將它「從公開名單上除名」而已,亦即此後別人無法再搜尋到這個版本的套件。這是因為套件一旦公開發布,就可能已經有某個專案參考到這個套件,並且在某個時間點需要重新下載該套件(透過 NuGet Package Restore 機制)並重新建置整個專案。要是 NuGet 允許作者刪除原先公開發布至伺服器的套件,很可能會造成某些專案在某天突然無法建置成功。
註:寫完這篇後,我已經把 HLT 套件從 NuGet.org 伺服器上除名,所以找不到了。我另外起了一個新的:Yalib(名稱很普通,因為我實在想不到什麼好名稱),詳情寫於下一篇筆記

小結

照本文的步驟做過一遍之後,基本上已經會使用下列 NuGet 指令:
  • nuget Pack (打包)
  • nuget Push (發布)
  • nuget SetApiKey (保存 API Key 至本機電腦,這樣以後每次發布時就不用再敲一次 API Key)
  • nuget Delete (將指定版本的套件從伺服器上除名,但實體檔案仍在,仍可下載,只是搜不會出現在搜尋結果中)
後續功課:

參考資料


Post Comments

技術提供:Blogger.