ASP.NET Core发布至IIS后出现BadImageFormatException程序集加载错误如何解决?
解决ASP.NET Core发布至IIS后加载系统DLL引发的BadImageFormatException问题
这个问题我之前也碰到过,根源就是你的代码遍历了发布目录下所有.dll文件,其中包含了Windows系统的API集DLL(比如api-ms-win-core-console-l1-1-0.dll这类)——这些是原生系统库,根本不是.NET程序集,强行用Assembly.Load加载肯定会抛出异常。下面给你几个针对性的解决方案,按推荐程度排序:
方案1:过滤已知的系统非.NET DLL
直接在获取文件路径时,排除那些明显是系统原生库的文件名,比如api-ms-win-开头的,还有CLR运行时的原生组件:
public static List<Type> FromAssembliesMatching<TType>(this AppDomain currentDomain, string searchPattern) { var referencedPaths = Directory.GetFiles(currentDomain.BaseDirectory, "*.dll") // 排除系统原生DLL .Where(path => !Path.GetFileName(path).StartsWith("api-ms-win-", StringComparison.OrdinalIgnoreCase) && !Path.GetFileName(path).Equals("clrcompression.dll", StringComparison.OrdinalIgnoreCase) && !Path.GetFileName(path).Equals("clrjit.dll", StringComparison.OrdinalIgnoreCase) && !Path.GetFileName(path).Equals("Microsoft.Windows.Common-Controls.dll", StringComparison.OrdinalIgnoreCase)) .ToList(); var assemblies = referencedPaths .Select(path => currentDomain.Load(AssemblyName.GetAssemblyName(path))) .ToList(); var types = assemblies.SelectMany(s => s.GetTypes() .Where(t => typeof(TType).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)) .ToList(); return types; }
方案2:结合Try-Catch容错,跳过加载失败的DLL
有些系统DLL的文件名可能不在上面的过滤列表里,这时可以在加载程序集时用try-catch捕获异常,直接跳过无法加载的文件:
public static List<Type> FromAssembliesMatching<TType>(this AppDomain currentDomain, string searchPattern) { var referencedPaths = Directory.GetFiles(currentDomain.BaseDirectory, "*.dll").ToList(); var assemblies = new List<Assembly>(); foreach (var path in referencedPaths) { try { var assemblyName = AssemblyName.GetAssemblyName(path); assemblies.Add(currentDomain.Load(assemblyName)); } catch (BadImageFormatException) { // 跳过非.NET程序集 continue; } catch (FileLoadException) { // 跳过已加载或无法加载的程序集 continue; } } var types = assemblies.SelectMany(s => s.GetTypes() .Where(t => typeof(TType).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)) .ToList(); return types; }
方案3:只加载你的应用相关程序集(最推荐)
如果你的应用程序集有统一的命名规则(比如都以YourCompany.或YourApp.开头),可以直接根据程序集名称过滤,只加载你自己的业务程序集和依赖的第三方.NET库,完全避免碰系统DLL:
public static List<Type> FromAssembliesMatching<TType>(this AppDomain currentDomain, string searchPattern) { var referencedPaths = Directory.GetFiles(currentDomain.BaseDirectory, "*.dll").ToList(); var assemblies = new List<Assembly>(); foreach (var path in referencedPaths) { try { var assemblyName = AssemblyName.GetAssemblyName(path); // 只加载你的应用程序集和信任的第三方库 if (assemblyName.FullName.StartsWith("YourApp.") || assemblyName.FullName.StartsWith("Newtonsoft.Json") || assemblyName.FullName.StartsWith("AutoMapper")) { assemblies.Add(currentDomain.Load(assemblyName)); } } catch (Exception) { continue; } } var types = assemblies.SelectMany(s => s.GetTypes() .Where(t => typeof(TType).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)) .ToList(); return types; }
额外提示
在ASP.NET Core中,其实还有更优雅的方式来发现接口实现类——比如利用依赖注入的IServiceCollection,或者使用AssemblyLoadContext来安全地加载程序集,避免直接遍历所有DLL的粗暴方式。不过上面的方案已经能快速解决你当前的问题。
内容的提问来源于stack exchange,提问作者barteloma
相关产品推荐
相关产品推荐

