起因
經手一個asp.net 逐步轉 asp.net core的項目,里面有一個經常變動的插件模塊,每次插件增刪的時候都要去改加載的地方,遂改成了根據命名規則自動加載,下面是很容易百度到的一句:
var plugins = AppDomain.CurrentDomain.GetAssemblies().Where(ab => ab.GetName().Name.StartsWith("Plugin.")).ToArray();
asp.net部分調試正常后發到iis上,沒出現任何問題,然后過一會兒再訪問發現部分插件沒有加載;iis目錄重新覆蓋打包文件,調用正常,重啟該web站點,問題重現。
分析
短暫的震驚之后,趕緊分析這肯定跟iis的回收有關,立即轉為面向搜索引擎編程,查詢關鍵字AppDomain GetAssemblies iis missing,很快找到原因;簡單概括為:AppDomain為應用程序域,GetAssemblies()只會獲取到已加載到當前域的程序集,iis應該是在站點目錄文件更新之后第一次會加載所有的,回收或重啟之后就只加載應用程序初始化必需的部分(后半部分是推斷,不深究了,后面也會被替換掉)。
解決辦法
1.程序啟動的時候把當前目錄所有的dll都手動調用Assembly.Load()一遍就行了。
2.顯然1不夠優雅;這里asp.net與asp.net core就有差異了。asp.net用到了core首要干掉的 System.Web.dll(顯然winform不會有這個問題);asp.net core使用了本身有包含的 Microsoft.Extensions.DependencyModel 。
asp.net: var plugins = BuildManager.GetReferencedAssemblies().Cast<Assembly>().Where(ab => ab.GetName().Name.StartsWith("Plugin.*")).ToArray();
asp.net core: var plugins = DependencyContext.Default.RuntimeLibraries.Where(o => o.Name.StartsWith("Plugin.")).Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
最後
相關參考:
https://www.michael-whelan.net/replacing-appdomain-in-dotnet-core/
有些坑即使再淺,也得自己踩過才會知道。