dotnet 警惕 Assembly.Location 返回空

在大部分情況下,獲取當前所運行的應用程序的所在路徑時,常用的就是 Assembly.Location 屬性,按照之前的經驗,使用 Assembly.Location 是最爲穩定的做法,然而在 dotnet 發佈單文件時,此屬性將會爲空,導致一些不符合預期的行爲

通過 Assembly.Location 屬性可以返回程序集所在的文件路徑,這個一個比較穩定的獲取某個路徑方式,至少比獲取當前的工作路徑 Environment.CurrentDirectoryDirectory.GetCurrentDirectory() 都要穩定得多。每次使用 Assembly.Location 都是返回程序集所在的文件路徑,而工作路徑 Environment.CurrentDirectoryDirectory.GetCurrentDirectory() 則是返回當前的工作路徑,而大家都知道,工作路徑是可以非常簡單的被進行更改的,從而導致每次調用 Environment.CurrentDirectoryDirectory.GetCurrentDirectory() 都可以返回不同的值。當然了,是否使用工作路徑,這也是看大家的需求的

如果大家在閱讀以上內容時,還沒有工作路徑的概念,還請先自行了解一下工作路徑是什麼以及工作路徑的用途是什麼

在單文件發佈這個功能之前,當咱需要獲取當前的應用程序安裝路徑,在不考慮插件 DLL 存在的情況下,我是推薦使用 Assembly.Location 屬性獲取當前的應用程序所在的文件夾的,大概的代碼如下

string installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;

這裏無論是採用 GetExecutingAssembly 也好,還是 GetEntryAssembly 方法都對於應用程序來說是正確的。但是由於單元測試下是沒有入口的程序集的也就是 GetEntryAssembly 將返回空,於是此時換成 GetExecutingAssembly 獲取當前正在運行的代碼所在的程序集將是更加穩定的

通過以上方式獲取應用程序路徑將比使用 AppDomainSetup.ApplicationBase 更加穩定,如以下代碼是通過 AppDomainSetup.ApplicationBase 獲取路徑

// 以下代碼是不推薦的
string? installFolder = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

然而原本比較穩定的 Assembly.Location 屬性將在進行單文件發佈時,返回空字符串。這就讓許多現有的邏輯不能正常工作,好在發佈單文件時,將會看到 VisualStudio 的以下提示內容

IL3000: Avoid accessing Assembly file path when publishing as a single file

這時候的推薦使用的是 AppContext.BaseDirectory 屬性,這個屬性也是用來返回當前應用程序的安裝路徑的穩定屬性

換句話說就是在使用 dotnet core 時,無論是 .NET Core 3.1 還是 dotnet 6 版本,在獲取當前應用程序的安裝路徑時,都可以使用 AppContext.BaseDirectory 屬性。使用這個屬性不僅代碼短,且穩定

那此時就有夥伴會疑惑,爲什麼我之前推薦都是使用 Assembly.Location 屬性。這是因爲我的許多基礎庫和項目那會都需要兼容 .NET Framework 4.5 版本,而 AppContext.BaseDirectory 是在 .NET Framework 4.6 之後才引入的,這就是爲什麼我沒有推薦過這個屬性的原因

如果自己的項目裏面有大量的舊代碼都是採用 Assembly.Location 屬性,感覺改不動,或者是在基礎庫裏面就是採用 Assembly.Location 屬性的,那可以使用配置方式切換爲兼容邏輯,如下面代碼

AppContext.SetSwitch("Switch.System.Reflection.Assembly.SimulatedLocationInBaseDirectory", true);

以上配置推薦加在 Main 函數第一句話裏面,加上以上配置之後,即可讓 Assembly.Location 屬性返回的是當前單文件的路徑,而不會返回空字符串

以上的配置內容是在 https://github.com/dotnet/corert/issues/5467 裏面大佬提供的

更多博客內容請參閱我的 博客導航博客園的合集

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章