只有累積,沒有奇蹟

2018年12月27日 星期四

[.NET] 無法載入檔案或組件 'Newtonsoft.Json' 或其相依性的其中之一 (發生例外狀況於 HRESULT: 0x80131040)

問題
接獲同事報案,反應在測試環境出現以下錯誤訊息 無法載入檔案或組件 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' 或其相依性的其中之一。 找到的組件資訊清單定義與組件參考不符。 (發生例外狀況於 HRESULT: 0x80131040) ,實際專案底下 bin 資料夾該 dll 是存在的,心想這問題每隔一陣子都會遇到決定不在挑戰大腦記憶體,將這問題解法記錄下來

探索問題
有踩過這雷的人就會很快知道問題,是多個專案參考到的 dll 版本不同造成,其實仔細看錯誤網頁中有提到幾個關鍵字 組件繫結失敗,跟 google 大神請教後使用 Fuslogvw.exe 可以查到相關線索Fuslogvw (Assembly Binding Log Viewer) 能夠查看應用程式在執行時組件繫結的 Log 資訊與紀錄,協助釐清應用程式無法執行的原因是因為佈署到錯誤的資料夾或是版本號無法對應的問題,且隨著 Visual Studio 一起安裝(同捆包概念),這裡簡單介紹如何使用

開啟 Fuslogvw 
Step 1 : 左下角開始 > 輸入 "Prompt"  >  點選 Developer Command Prompt for VS 2017 
( 補充 : 記得要用管理者權限,否則會無法使用相關功能 )
Step 2 : 在 Developer Command Prompt for VS 2017 輸入 Fuslogvw ,按下 Enter
Step 3 : 會跳出 組件繫結紀錄檢視器 (如果無法按就是沒用 admin 權限開啟)

綁定繫結紀錄 
接下來步驟是說明如何透過 Fuslogvw.exe 的設定取得應用程式中 assembly Binding 的紀錄與資訊
Step 1 : 按下設定,設定以下兩個資訊
  • 啟用紀錄 : 預設是停用紀錄,有紀錄失敗的組件繫結與記錄所有的內容,我比較貪心選擇全部
  • 紀錄檔案的位置 : 設定紀錄 Log 檔的位置,我選擇有個暫存好找的位置存放,看個人喜好
Step 2 : 為了要取得組件繫結失敗 log 資訊,我們再重新執行一次應用程式
Step 3 : 執行完應用程式後按下 重新整理,就會發現左邊區塊出現 assembly Binding 的 log 資訊,像是應用程式assembly 以及 Log的時間等資訊,這樣就代表 Fuslogvw.exe 繫結成功


檢視記錄檔 
回到最初的問題錯誤訊息是 Newtonsoft.Json 載入失敗,這時可以透過 Fuslogvw 查看載入該組件的紀錄,點選 Newtonsoft.Json 後按 檢視記錄檔

Newtonsoft.Json 載入失敗訊息如下
  1. *** 組件繫結器記錄項目 (2018/12/27 @ 上午 04:08:15) ***
  2.  
  3. 作業失敗。
  4. 繫結結果: hr = 0x80131040 沒有可用的描述。
  5.  
  6. 組件管理員的載入來源: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
  7. 正在可執行檔下執行 c:\windows\system32\inetsrv\w3wp.exe
  8. --- 下列是詳細的錯誤記錄。
  9.  
  10. === 繫結前狀態資訊 ===
  11. 記錄: DisplayName = Newtonsoft.Json
  12. (Partial)
  13. 警告: 提供了組件的部分繫結資訊:
  14. 警告: 組件名稱: Newtonsoft.Json | 網域 ID: 2
  15. 警告: 如果只提供部分的組件顯示名稱,就會發生部分繫結。
  16. 警告: 這可能會使繫結器載入不正確的組件。
  17. 警告: 建議為組件提供完全指定的文字識別,
  18. 警告: 該識別是由簡單名稱、版本、文化特性和公開金鑰語彙基元組成。
  19. 警告: 如需詳細資訊和這個問題的一般解決方法,請參閱白皮書 http://go.microsoft.com/fwlink/?LinkId=109270。
  20. 記錄: Appbase = file:///D:/application folder/
  21. 記錄: 初始 PrivatePath = D:\application folder\bin
  22. 記錄: 動態基底 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\applicationName\f8aec008
  23. 記錄: 快取基底 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\applicationName\f8aec008
  24. 記錄: AppName = 57a93a57
  25. 正在呼叫組件 : (Unknown)。
  26. ===
  27. 記錄: 此繫結在 default 載入內容中開始。
  28. 記錄: 正在使用應用程式組態檔: D:\application folder\web.config
  29. 記錄: 使用主機組態檔: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
  30. 記錄: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config 使用電腦組態檔。
  31. 記錄: 目前不會套用原則至參考 (私用、自訂、部分或以位置為主的組件繫結)。
  32. 記錄: 正在嘗試從新的 URL file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/applicationName/f8aec008/57a93a57/Newtonsoft.Json.DLL 下載。
  33. 記錄: 正在嘗試從新的 URL file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/applicationName/f8aec008/57a93a57/Newtonsoft.Json/Newtonsoft.Json.DLL 下載。
  34. 記錄: 正在嘗試從新的 URL file:///D:/application folder/bin/Newtonsoft.Json.DLL 下載。
  35. 記錄: 已順利下載組件。正在嘗試安裝檔案: D:\application folder\bin\Newtonsoft.Json.dll
  36. 記錄: 進入下載快取安裝階段。
  37. 記錄: 組態名稱為: Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
  38. 記錄: 從應用程式目錄中執行部分指定的組件繫結成功。必須重新套用原則。
  39. 記錄: 正在使用應用程式組態檔: D:\application folder\web.config
  40. 記錄: 使用主機組態檔: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
  41. 記錄: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config 使用電腦組態檔。
  42. 記錄: 在應用程式組態檔中找到重新導向: 重新導向 8.0.0.0 11.0.0.0
  43. 記錄: 原則後參考: Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
  44. 記錄: GAC 查閱失敗。
  45. 記錄: 原則後組件參考必須再進行探查。
  46. 記錄: 正在嘗試從新的 URL file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/applicationName/f8aec008/57a93a57/Newtonsoft.Json.DLL 下載。
  47. 記錄: 正在嘗試從新的 URL file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/applicationName/f8aec008/57a93a57/Newtonsoft.Json/Newtonsoft.Json.DLL 下載。
  48. 記錄: 正在嘗試從新的 URL file:///D:/application folder/bin/Newtonsoft.Json.DLL 下載。
  49. 記錄: 已順利下載組件。正在嘗試安裝檔案: D:\application folder\bin\Newtonsoft.Json.dll
  50. 記錄: 進入下載快取安裝階段。
  51. 記錄: 組態名稱為: Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
  52. 警告: 比較組件名稱發現不符項目: 主要版本
  53. 錯誤: 組件參考不符合找到的組件定義。
  54. 錯誤: 安裝失敗,hr = 0x80131040
  55. 錯誤: 無法完成組件的安裝 (hr = 0x80131040)。已終止探查。
  56.  
小弟用我淺薄的知識簡單說明一下 Log : 
  • Line 11 : 說明應用程式要繫結的組鍵名稱
  • Line 20-21 : 本次要載入的應用程式路徑,dll folder位置
  • Line 22-23 : IIS 預設會把編譯後的應用程式資料夾存放在 Framwork安裝目錄 \ Temporary ASP.NET Files 目錄下,詳細可以參考 Understanding ASP.NET Dynamic Compilation 
  • Line 35-37 : 找到繫結組件的 dll 位置與版本等資訊
  • Line 38-39 : Web.Config 中可以設定 assemblyBinding 的版本號與關聯提供載入組鍵時參考詳細可以參考 MSDN 
  • Line 44 : GAC 確認失敗Global Assembly Cache 
  • Line 49-51 : 嘗試從應用程式資料夾底下的dll folder 安裝 Newtonsoft.Json 組鍵,這裡抓到版本號是 8.0.3
  • Line 52-53 : 發現版本不同指定的版號是 11.0.3 安裝的卻是 8.0.3
  • Line 54 : 安裝失敗顯示錯誤訊息 HRESULT: 0x80131040
解法
透過 Fuslogvw 分析完案發現場,確認是 dll 版本不同原因造成,在與同事確認專案的架構確實有多個專案參考來參考去的現象Class lib A 與 Class lib B 都依賴於 Class lib C只要 Class lib C 版本不同時,就會發生執行到不相配的 Json 版本的 dll 時,就會造成 runtime exception發生原因了解了接著看如何解決這問題

設定 assemblyBinding
在使用工具查看 Log 時候可以發現繫結過程中,會去參考 Web.Config 的 assemblyBinding 元素定義來加載 dll 內容,加上以下設定,告訴它在載入組件的過程中要綁定某個版本 ( 相關說明請服用 MSDN )

重建專案檔
目的 : 讓 Visual Studio 重啟加載專案檔及相關設定,重新檢查 Package 之間依賴性
設定方式 : 專案檔右鍵 > Clean > 重啟 Visual Studio > 重新 Build 專案 > 設定為 Release > 開始 debug

重裝異常的 Dll 
目的 : 讓異常的 dll 版本一致 
Step 1 : 專案 Reference > 異常 Dll 右鍵 > 屬性 > 顯示版本 
Step 2 : 到有使用異常 dll 的專案 > Manage Nuget Packages > 選擇 dll > Update version
成功訊息
透過以上方式,應用程式就可以正常使用,在使用 Fuslogvw 查看 Newtonsoft.Json 已正常載入,正常載入訊息如下,宣告破案 (握拳

參考
Could not load file or assembly or one of its dependencies
Fuslogvw.exe (Assembly Binding Log Viewer)
<assemblyBinding>元素<執行階段>

Related Posts:

  • [VS2017] 提升 Resharper 在 Visual Studio IDE 執行速度前言  Visual Studio 是地表上最強的開發工具,最近發現在安裝完 Resharper 後開啟專案時都會遇到 載入專案的速度變慢的問題,Visual Studio 會在上方提示 JetBrains ReSharper Ultimate’ likely caused 8 seconds of unresponsiveness. Disabling it may improve your experi… Read More
  • [.NET] 選擇性參數 (Optional parameters) 的另一種選擇 - OptionalAttribute前言  上一篇文章介紹 了具名引數 (named argument) 的用法,其中被呼叫的方法是使用 C# 4.0 的 optionnal argument 達到方法選擇性參數,過去待過的公司 method 遇到選擇性參數時大多使用 optionnal argument 方式來解決,但其實有另外一種方式可以使用 optionAttribute,這篇就簡單介紹針對同樣需求兩者的寫法 使用… Read More
  • [UnitTest] NUnit 測試例外 exception - 使用 Assert.Throws前言 介紹了如何使用 NUnit 撰寫單元測試、使用 TestCase 處理參數化方法測試不同情境,如果寫單元測試時想要驗證例外狀況時該怎麼處理 ? NUnit 分別在 NUnit 2 & 3 中提供 ExpectedException、Assert.Throws 讓開發者處理測試例外的情境,以下簡單分享如何使用 使用說明 要驗證的 sample Code 如下,Example 類別有個 WorkTime 方法內容為… Read More
  • [Docker] Image operating system "windows" cannot be used on this platform問題 接獲同事詢問在安裝完 Docker for Windows 之後,練習指令 docker pull image 時候跳出異常訊息,訊息內容為 image operating system "windows" cannot be used on this platform ,回想起自己一開始觀念不熟悉時也發生過類似問題,錯誤訊息如下所示 PS C:\marcustung> docker pull someone/image:l… Read More
  • [UnitTest] NUnit 參數測試 - 使用 TestCase、TestCaseSource前言 上一篇 NUnit 入門教學 簡單介紹如何使用 NUnit 撰寫單元測試,但在實務上在寫單元測試時不會那麼單純,舉例來說如果要針對某個 method 進行種不同情境的測試,僅差在不同的參數來多次驗證結果, 在 NUnit 官方文件中有提供很多好用的方法像是 TestCase、TestCaseSource 等方式可以解決此問題,以下會簡單分享小小研究後的說明與差異性,依據適合的情境使用相對應的方法 解決方案 要驗證的 sample… Read More

0 意見:

張貼留言

Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com