這年頭用Visual Studio寫程式已經離不開NuGet了!NuGet會在每個專案新増packages.config記錄已安裝Package及版本,在解決方案(.sln)檔所在資料夾則會建立packages保存各專案的NuGet Package DLL實體,放在解決方案層級的好處是方便Package檔案共享,專案A裝過NLog,專案B要安裝NLog時就不需要重新下載,直接參照packages裡的nlog.dll就好。

從NuGet 2.7起,Visual Studio預設啟用Automatic Packages Restore功能,只要以下兩佪選項沒有被關閉,VS會在每次編譯時檢查各專案的packages.config,自動補齊欠缺的Package。

在NuGet 2.7之前的版本,採用的還原做法是所謂MSBuild-Integrated Package Restore,如要採用這種做法,需如下圖在解決方案按右鍵啟用設定,之後Visual Studio會略過Automatic Package Restore,改用舊做法。

當啟用MSBuild-Integrated Restore,除了packages目錄,解決方案資料夾下還會再多一個.nuget資料夾,裡面有NuGet.exe、NuGet.config、NuGet.targets,方便建置時自動由NuGet補足缺少的Package。(但此點不適用Web Site Project)

新舊做法相比,Automatic Package Restore有以下優點:

  1. 不需額外操作設定,開發者糊里糊塗不知不覺間就能享受到Package自動還原功能。
  2. 不需額外新增.nuget資料夾及檔案
  3. Package還原工作搶在MSBuild之前由Visual Studio執行,讓MSBuild相關的擴充套件能在編譯前被準備好。 
  4. 支援Web Site Project!(WSP:嗚… 總算還有人記得我)

除此之外,也有透過命令列還原Package的做法,更多細節可參考NuGet文件

使用NuGet Package Restore可減少原始碼傳送及封存時的資料量。packages資料夾包含大量dll檔,容量常常高達數百MB,啟用Package Restore後,packages不需隨原始碼打包,對方可在建置專案時再由NuGet即時下載安裝。

「packages跟.nuget資料夾該不該進版控?」的問題困擾我好一陣子了,之前沒掌握底層運作的眉角,常被一些「靈異現象」整得七葷八素,直到累積一些心得後,才有較具備的概念!(老話一句,會覺得「暗!見鬼了」多半是因為了解不夠透徹,線索掌握不足所致,真相大白後便會驚覺一切都符合科學邏輯,電腦永遠是死板板照指令辦事,從不背叛任何人。相較於江湖事,單純豈止十萬倍? XD)

packages進版控跟不進版控實務上都可行,但屬兩種不同策略,實踐時一些細節要到位,不然會搞到你欲哭無淚。

策略一:packages不進版控

新版Visual Studio與NuGet 2.7+預設已開啟Automatic Package Restore功能,理論上什麼都不做就可以做到自動邏原,故大部分的情況下packages並不需要簽入TFS。

如果你選擇使用MSBuild-Integrated Package Restore(例如:要配合Build Service或批次自動編譯),記得要開啟Enable NuGet Package Restore選項,並確認packages目錄沒有簽入TFS。之前遇過案例:package被誤簽入TFS,但預設dll、exe檔案型別不會簽入。因此TFS版控空有packages各Package的完整目錄結構,獨缺最重要的dll檔。另一位同事取得最新版本編譯專案,NuGet試著還原Package,發現該Package版本的目錄已存在於packages,便認定已下載略過還原程序。結局是專案依循參數路徑找不到dll,若不是直接報錯,就是靠Visual Studio顯神通找到自以為合用的dll頂替,搞出靈異現象

另外,已啟用MSBuild-Integrated Package Restore的專案可以改為Automatic Package Restore,方法可以參考這篇說明

策略二:packages進版控

如果想避免重複下載Package,或是建置環境無法連上NuGet,則可選擇將packages全部簽入TFS版控。如此另一方在取得最新版原始碼時,所需NuGet Package dll檔一併就位,直接編譯即可,不需再花功夫下載。

但有幾點要注意:

  1. 如果已Enable NuGet Package Restore,.nuget資料夾也要簽入
    新版NuGet會在csproj中加入以下檢查,Visual Studio能自動補上.nuget資料夾,但使用MSBuild編譯時便會因.nuget不存在而出錯。(更新:實測新版NuGet及MSBuild已無此需要)
    排版顯示純文字
    <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
        <PropertyGroup>
          <ErrorText>This project references NuGet package(s) that are missing on 
    this computer. Enable NuGet Package Restore to download them.  For more 
    information, see http://go.microsoft.com/fwlink/?LinkID=322105. 
    The missing file is {0}.
        </ErrorText>
        </PropertyGroup>
        <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" 
     Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
      </Target>
  2. 簽入.nuget、packages時要確認有包含dll及exe
    預設TFS在簽入資料夾時將排除exe及dll,要記得將它們從排除清單(Excluded items)再拉回來。
     
    每次簽入都要手動補回DLL有點繁瑣,Franma提供一個好方法:可在packages目錄加入.tfIgnore要求TFS不排除DLL,之後簽入packages資料夾就能把DLL進版控囉!
  3. NuGet Package新増或升級時記得簽入TFS
    由於不再依賴NuGet自動補檔與升級,Package如有異動記得要簽入

PS: 感謝網友徐胖胖回饋Automatic Package Restore相關資訊


Comments

# by Franma

黑大,用策略一的話記得要搭配 Ignore 機制,這樣子就不用擔心有人把 DLL 漏了 :) 另外,若是想要做 CI 的話還是建議用策略一比較快,不然每次建置都要重新下載也是蠻花時間的。

# by Jeffrey

to Franma,謝謝補充,.tfIgnore這招很讚,已加入本文。

Post a comment