dotnet pack 打包文件版本號引發 "Could not load file or assembly" 問題

若是不是遇到,真的不會想到,代碼世界的問題真是千奇百怪,此次遇到的是 dotnet pack 打包文件版本號引發的問題。html

以前進行 nuget 打包都是在 Visual Studio build 時進行,版本號時經過 .csproj 中的 VersionPrefix 指定,沒遇到問題。linux

最近,改成經過 shell 腳本在 linux 上打包,開始的 shell 腳本是怎麼寫的:git

dotnet pack -c Release /p:version=$(git tag --sort=committerdate | tail -1 )

後來發現 dotnet pack 不能自動 build 項目,這個問題不是從哪一個版本的 .net core cli 開始出現的。shell

爲了解決這個問題,在 dotnet pack 命令以前添加了 dotnet build 命令:json

dotnet build -c Release
dotnet pack -c Release /p:version=$(git tag --sort=committerdate | tail -1 ) 

採用這個腳本發包後,最近幾回發包遇到了奇怪的問題,好比發佈了 EnyimMemcached 2.2 包,在引發該包的 A 項目中升級到 EnyimMemcached 2.2,而 A 項目所引用的其餘 nuget 包也引用了 EnyimMemcached 但引用的是舊版 EnyimMemcached 2.1.12 ,build 沒問題,運行時卻報下面的錯誤,整個應用都沒法啓動。post

System.IO.FileLoadException: Could not load file or assembly 'EnyimMemcachedCore, Version=2.1.12.0, Culture=neutral, PublicKeyToken=null'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'EnyimMemcachedCore, Version=2.1.12.0, Culture=neutral, PublicKeyToken=null'
   at System.Signature.GetSignature(Void* pCorSig, Int32 cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType)

對於這樣的依賴同一個包的不一樣版本問題,.net core 中已經進行了有效解決,若是存在版本衝突,在 build 時就能發現,好比 解決 .net core 中 nuget 包版本衝突問題 ,只要 build 經過,基本不會出現上面的問題,.net core runtime 會自動使用最高版本。ui

而咱們如今卻遇到了這個 .net core 已經解決的問題,讓人莫名其妙,無從下手。今天再次遇到這個問題時,想到把包解開看看其中有沒有與運行時相關的元數據信息。spa

解開一看,除了 dll 文件,沒有其餘用於運行時的文件,在查看這個 dll 文件的信息時發現了線索:.net

 

不對,文件版本號怎麼是 1.0 ,打的明明是 2.2 的包?日誌

Review 打包腳本後恍然大悟

dotnet build -c Release

dll 文件是在 build 時生成的,Build 時沒有添加版本信息,因而使用了默認版本號1.0。

趕忙改進腳本試試

VERSION=$(git tag --sort=committerdate | tail -1)
dotnet build /p:version=$VERSION -c Release Enyim.Caching
dotnet pack -c Release /p:version=$VERSION Enyim.Caching

這樣改進後,打出的包中的 dll 文件版本就與包的版本就一致了

在項目中升級到這個包,問題也就解決了。

原來,.net core 在 build 時只檢查 nuget 包的版本號,不檢查包中 dll 程序集文件的版本號,而 .net core runtime 在運行時會檢查程序集文件的版本號。而咱們遇到的問題就是因爲 build 時與運行時的檢查機制不一致,形成錯誤的文件版本號沒有在 build 時被檢查出來,從而在應用運行的時候才發現,大大增長了問題的排查難度。

爲何必定要在運行時檢查程序集文件的版本號並且在版本號出現問題時讓整個應用都沒法啓動?反正就這一個文件,寫個告警日誌,繼續用這個文件就是了,若是沒法使用這個文件,再讓整個應用掛掉也不遲,這個地方有點想不通。

今天的發現也讓以前的另一個疑問有了答案,以前在 .NET Core 2.2 中遇到了 System.Data.SqlClient 的問題,想看看最新版的 corefx 是否解決了這個問題,因而簽出最新版的 corefx 代碼 build 出了 System.Data.SqlClient.dll 替換 .NET Core 2.2 中的同名文件,運行時也老是報錯 "Could not load file or assembly" ,只有簽出 release/2.2 分支的代碼 build 才行,原來也是文件版本號的問題,只要修改一下文件版本號就能解決。

另外,程序集的依賴信息保存在 .deps.json 文件中,若是不能修改程序集文件的版本號,應該能夠經過修改 .deps.json 文件中 runtime 配置的 fileVersion 值來實現。

"runtime": {
  "lib/netstandard2.0/EnyimMemcachedCore.dll": {
    "assemblyVersion": "2.2.2.0",
    "fileVersion": "2.2.2.0"
  }
}
相關文章
相關標籤/搜索