ความจริงอันโหดร้ายของ NuGet Package Restore

image2

เนื่องจากตอนนี้ผมกำลังพยายามจะตั้งค่า Continuous Integration Server โดยใช้ TFS Build ซึ่งก็พบกับปัญหานี้บ่อยมากครับ คือ Error ที่เขียนว่า

D:\Path\To\Project.csproj (122): 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=317567

หลังจากพยายามอยู่ 1 วันเต็มๆ ผมเพิ่งจะพบว่า จริงๆ แล้ว นี่ไม่ใช่วิธีที่ถูกต้อง ในการตั้งค่า NuGet Package Restore ครับ

ปัญหาที่เราเจอ โดยรวมก็คือ เวลาที่ Build ใน Visual Studio จะสามารถ Build ได้ตามปกติ แต่ว่าไม่สามารถสั่ง Build ด้วย MSBuild ได้ โดยจะติดปัญหาเหล่านี้ครับ

  1. จะต้องทำการ Build 2 รอบ เนื่องจากรอบแรก MSBuild จะแจ้ง Error ว่า ต้องทำการ Rebuild อีกรอบเพราะว่ามีการ Restore Package ตรงนี้ ทำให้เกิดปัญหาว่า เราไม่สามารถตั้งค่าให้ Build แบบ Clean Workspace ได้ เพราะว่าการ Clean Workspace จะลบ Folder package ของ NuGet ไปด้วย ทำให้ Build ไม่มีวันที่จะ Succeed ได้ครับ
  2. บางโปรเจค แสดง Error ว่า:

    D:\Path\To\Project.csproj (122): 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=317567

    ทั้งที่ผมได้ทำการ Enable Package Restore ที่ตัว Solution แล้ว

หลังจากตรวจสอบ Documentation ของ Nuget อีกครั้ง จึงได้พบในหน้านี้ http://docs.nuget.org/docs/reference/package-restore ว่า

Prior to NuGet 2.7, an MSBuild-Integrated Package Restore approach was used and promoted. While this approach is still available, the NuGet team suggests using the Automatic Package Restore and Command-Line Package Restore instead.

อ้าว เปลี่ยนไม่รู้ตัว แต่ว่ายังมีเมนูให้กดอยู่ด้วยนะใน Visual Studio

ดังนั้น ผมจึงต้องเริ่มทำการ Migrate Project ทั้งหมด ออกจากวิธีเก่าแล้วสินะ ที่สำคัญคือ วิธีนี้มันก็มีปัญหามากเสียด้วย ไม่เคยจะใช้งานได้ดีเลยตั้งแต่ใช้งานมา ก็เลยต้องลองทำตามขั้นตอนที่บอกไว้ในนี้ครับ http://docs.nuget.org/docs/workflows/migrating-to-automatic-package-restore ผมขอแปลเป็นภาษาไทยให้ก็แล้วกันนะ ดังนี้

  1. ถ้าใน Project มี Folder ชื่อว่า .nuget ทำการลบไฟล์ Nuget.exe แลพ Nuget.Targets ออก เหลือไฟล์ Nuget.Config เอาไว้นะครับ

    image8
  2. ปิด Visual Studio ก่อน ไม่อย่างนั้น Visual Studio จะทำการเพิ่มข้อความที่เราลบไป กลับเข้ามาใหม่ครับ
  3. จากนั้น เราจะต้องทำการแก้ไขไฟล์ Project ทุกไฟล์ใน Solution เพื่อเอา Configuration ของ Nuget ออก แน่นอนว่าการทำด้วยมือคงเป็นเรื่องที่ยุ่งยาก และเสี่ยงต่อความผิดพลาดได้ง่าย ผมเลยจะใช้ Notepad++ ในการช่วยงานเราครับ

    ใน Notepad++ จะมีคำสั่งชื่อว่า Find in Files (เปิดขึ้นมาด้วยการกด CTRL+F) ซึ่งสามารถค้นหาไฟล์ ที่มีข้อความข้างในตรงกับ Pattern ที่เรากำหนดได้ และยังสามารถ Replace ได้ด้วย อย่างในภาพตัวอย่างนี้ ผมกำลังจะลบ <RestorePackages>true</RestorePackages> ออกจากไฟล์ Project ทั้งหมด แทนที่ด้วยบรรทัดว่าง 1 บรรทัดแทน

    image11

    โดยข้อความที่เราต้องลบ มีดังนี้ครับ
    • <RestorePackages>true</RestorePackages>
    • <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />

      แต่ถ้าใน Document จะบอกว่า <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> นะครับ น่าจะเป็นเพราะ Nuget คนละเวอร์ชั่นกัน
    • <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />

      ใน Documentation จะบอกให้ลบทั้ง Tag ที่ชื่อว่า

      <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> แต่จากการพิจารณาดูแล้ว เฉพาะ <Error Condition นี้น่าจะเพียงพอแล้วครับ เพราะว่าเขียน Pattern ให้ลบออกยาก
  4. เปิด Solution ขึ้นมาใหม่ แล้วลบ Nuget.exe กับ Nuget.Targets ออกจาก Solution อย่าลืมดูว่า ไฟล์นี้ถูกลบออกจาก Source Control ด้วยนะครับ
    image17

 

เท่านี้ ก็จะเป็นการแก้ไขปัญหาT his 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=317567 ได้แล้วครับ โดยถ้าเปิดใน Visual Studio พวก Package ทั้งหมด จะถูก Restore ให้เราอัตโนมัติ