起因
经手一个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/
有些坑即使再浅,也得自己踩过才会知道。