錯誤的 HintPath 也可以在 Visual Studio 中建置,但 CI 的時候可能不行 | The Will Will Web

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

錯誤的 HintPath 也可以在 Visual Studio 中建置,但 CI 的時候可能不行

我在幫一個客戶 Code Review 並重構專案的時候,發現他們的專案在 Visual Studio 2019 都可以順利的建置專案,但是透過 Azure Pipelines 使用 MSBuild 建置卻會編譯失敗,錯誤訊息非常不清楚,真的是查了很久才想通問題的主因在哪裡,我覺得值得寫篇文章記錄一下。

錯誤訊息

發生建置失敗時,通常都是先透過 Log 找到蛛絲馬跡,首先映入眼簾的是「錯誤」訊息,總共有 68 個:

##[error]Common\Shared\CheckMod.cs(15,18): Error CS0234: The type or namespace name 'Mvc' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)
##[error]Common\Utils\AzureStorage.cs(8,17): Error CS0234: The type or namespace name 'Azure' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
##[error]Common\FTP\FtpUtils.cs(1,7): Error CS0246: The type or namespace name 'FluentFTP' could not be found (are you missing a using directive or an assembly reference?)
...
...

這錯誤很怪,我明明 NuGet Restore 都有成功,怎麼可能編譯時找不到命名空間呢?我在本機是可以編譯的啊!

一般來說,錯誤都解決不了,通常不會去找「警示」訊息,但我還是去看了,共有 30 個:

##[warning]C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): Warning MSB3245: Could not resolve this reference. Could not locate the assembly "AngleSharp, Version=0.14.0.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
##[warning]C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): Warning MSB3245: Could not resolve this reference. Could not locate the assembly "AngleSharp.Css, Version=0.14.2.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
##[warning]C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): Warning MSB3245: Could not resolve this reference. Could not locate the assembly "AntiXssLibrary, Version=4.3.0.0, Culture=neutral, PublicKeyToken=d127efab8a9c114f, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
##[warning]C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): Warning MSB3245: Could not resolve this reference. Could not locate the assembly "EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
...
...

他顯示 Check to make sure the assembly exists on disk 耶!但我的資料夾明明就有完整的 packages 目錄,套件也都有還原成功啊!

魔鬼總是出在細節裡,這段 Log 真的很難看出問題所在。我一開始只看出他「非常認真」的想找到 EntityFramework.dll 在哪裡,但最終就是找不到!

2021-09-08T09:59:25.0317073Z C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. [D:\a\1\s\Common.csproj]
2021-09-08T09:59:25.0319856Z    For SearchPath "{HintPathFromItem}".
2021-09-08T09:59:25.0320809Z    Considered "D:\a\1\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0321729Z    For SearchPath "{TargetFrameworkDirectory}".
2021-09-08T09:59:25.0322812Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0324318Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0326235Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0327345Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0329704Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0331000Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0332550Z    For SearchPath "{AssemblyFoldersFromConfig:C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\AssemblyFolders.config,v4.6.1}".
2021-09-08T09:59:25.0333890Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0334975Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0336185Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0337230Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\Extensions\Microsoft\SqlDb\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0338741Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\Extensions\Microsoft\SqlDb\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0339871Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\Extensions\Microsoft\SqlDb\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0341008Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0342446Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0343716Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0344976Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.5\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0346011Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.5\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0347336Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.5\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0348385Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0349711Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0350959Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0352430Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0353536Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0354501Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0355937Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.5\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0357043Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.5\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0358358Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.5\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0359726Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0360920Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0362581Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0364118Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0365506Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0366461Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v4.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0367645Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v2.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0368749Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v2.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0370328Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v2.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0371751Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VSSDK\VisualStudioIntegration\Common\Assemblies\v2.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0373197Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VSSDK\VisualStudioIntegration\Common\Assemblies\v2.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0374668Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VSSDK\VisualStudioIntegration\Common\Assemblies\v2.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0375585Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v2.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0376751Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v2.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0377919Z    Considered "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\v2.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0378757Z    For SearchPath "{Registry:Software\Microsoft\.NETFramework,v4.6.1,AssemblyFoldersEx}".
2021-09-08T09:59:25.0379755Z    Considered AssemblyFoldersEx locations.
2021-09-08T09:59:25.0380118Z    For SearchPath "{AssemblyFolders}".
2021-09-08T09:59:25.0380669Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0381945Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0382984Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0384254Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0385219Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0386357Z    Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0387438Z    Considered "C:\Program Files\IIS\Microsoft Web Deploy V3\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0388370Z    Considered "C:\Program Files\IIS\Microsoft Web Deploy V3\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0389534Z    Considered "C:\Program Files\IIS\Microsoft Web Deploy V3\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0390627Z    Considered "C:\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0391822Z    Considered "C:\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0393042Z    Considered "C:\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0394137Z    Considered "C:\Program Files (x86)\WiX Toolset v3.11\SDK\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0395074Z    Considered "C:\Program Files (x86)\WiX Toolset v3.11\SDK\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0395903Z    Considered "C:\Program Files (x86)\WiX Toolset v3.11\SDK\EntityFramework.exe", but it didn't exist.
2021-09-08T09:59:25.0396662Z    For SearchPath "{GAC}".
2021-09-08T09:59:25.0397574Z    Considered "EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL", which was not found in the GAC.
2021-09-08T09:59:25.0398536Z    For SearchPath "{RawFileName}".
2021-09-08T09:59:25.0399682Z    Considered treating "EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL" as a file name, but it didn't exist.
2021-09-08T09:59:25.0400706Z    For SearchPath "bin\Release\".
2021-09-08T09:59:25.0401283Z    Considered "bin\Release\EntityFramework.winmd", but it didn't exist.
2021-09-08T09:59:25.0402284Z    Considered "bin\Release\EntityFramework.dll", but it didn't exist.
2021-09-08T09:59:25.0403161Z    Considered "bin\Release\EntityFramework.exe", but it didn't exist.

我比較不能理解的地方是,在我自己的電腦用 MSBuild 是可以成功建置的,但是在 Azure Pipelines 的 Hosted Agent 用 MSBuild 就是找不到編譯所需的組件(Assembly)!

解決方法

我經常說:「寫 Code 需要靈感,解 Bug 需要創意」,沒靈感的時候還可以上網抄點 Code,但沒創意你就抓不到這種詭異的 Bug 了!

我最後的解決方法,還是靠眼睛看 Log,搭配創意的大腦思考每一段內容的蛛絲馬跡,最後被我找到這個線索:

Considered "D:\a\1\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll", but it didn't exist.

看出來了嗎?還沒?我們再看細一點:

Considered "D:\a\1\packages\..."

我突然恍然大悟,因為 Azure Pipelines 預設的 Source 路徑 (Build.SourcesDirectory) 是在 D:\a\1\s 目錄下,當我在專案根目錄執行 nuget restore 的時候,照理說 NuGet 的 packages 應是在 D:\a\1\s\packages 目錄才對,怎麼會變成 D:\a\1\packages 目錄呢?

最後我才想到可能是 *.csproj 裡面參考的組件路徑有誤,打開來一看,發現組件參考的 HintPath 路徑真的有錯,當我批次調整錯誤的路徑之後,專案就可以順利的在 CI 自動建置完成了! 😃

修正 HintPath 錯誤的路徑

問題主因

其實客戶的專案檔原本是好的,但是我們在合併不同專案的時候,有將幾個專案移動到上一層目錄,但是當下並沒有意識到 *.csproj 也要一併修改組件參考的相對路徑。由於 .NET Framework 大部分的組件參考都是相對於 packages 這個 NuGet 套件快取目錄的路徑,當我的專案往上移動一層時,專案檔中的路徑也要一併修改才行,這是我沒有注意到的地方! 🔥

這個問題最終未解的疑惑,就是不知道為什麼在我的電腦可以用 Visual Studio 2019 與 MSBuild 成功建置呢?是不是在其他電腦才不行?是否 MSBuild 的版本不同造成的差異?還是 Visual Studio 2019 版本不同造成的?這個問題等我下次遇到相同問題時再來研究了!

批次重裝所有 NuGet 套件

感謝 Poy Chang 的技術交流中心 分享以下 PowerShell 指令,這個命令可以在 Visual Studio 2019 的 Package Manager Console 底下執行,他會全自動找出所有專案的所有已安裝的 NuGet 套件,並且自動全部重新安裝! 👍

Get-Project -All | % { Get-Package -ProjectName $_.ProjectName | % { Update-Package $_.Id -Reinstall -ProjectName $_.ProjectName -IgnoreDependencies } }

在重新安裝完之後,所有的問題都會自動迎刃而解!

相關連結