.NET5加载ASP.NET Core WebApi程序集缺失Microsoft相关库问题咨询
为什么依赖文件不会自动复制到输出文件夹
从.NET Core 3.0开始,ASP.NET Core相关的核心程序集都被整合进了共享框架(Shared Framework),默认不会作为独立Nuget包被复制到项目输出目录,运行时会从系统级的共享框架安装路径加载这些依赖。你单独安装Microsoft.AspNetCore.Mvc.Core这类Nuget包也不会触发本地复制,因为这些包本质上只是指向共享框架的引用包,不包含实际的可执行二进制内容。
如果要强制WebApi项目输出所有依赖,只需要在WebApi项目的.csproj文件的<PropertyGroup>节点下添加配置:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
重新编译后所有相关依赖都会输出到bin目录。
如何正确读取已编译WebApi的控制器方法,现有实现的问题
现有实现的问题
你现在用Assembly.LoadFrom的方式需要加载目标程序集的全部依赖才能正常读取类型,一旦依赖不在当前程序的探测路径里就会抛出加载失败异常,这个方案的兼容性很差,尤其是面对基于共享框架编译的.NET 5+项目。
正确的实现方案
推荐用元数据读取的方式,不需要加载完整程序集,也不需要依赖目标程序的任何运行时依赖,就能直接提取控制器和方法信息。你可以使用System.Reflection.Metadata库实现:
- 先通过Nuget安装
System.Reflection.Metadata包 - 示例代码如下:
using System.IO; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; var assemblyPath = @"你的WebApi dll路径"; using var stream = File.OpenRead(assemblyPath); using var peReader = new PEReader(stream); var metadataReader = peReader.GetMetadataReader(); // 遍历所有类型 foreach (var typeDefHandle in metadataReader.TypeDefinitions) { var typeDef = metadataReader.GetTypeDefinition(typeDefHandle); var typeName = metadataReader.GetString(typeDef.Name); var namespaceName = metadataReader.GetString(typeDef.Namespace); // 判断是否是控制器:通常是继承自ControllerBase,且名称以Controller结尾 bool isController = false; // 遍历基类判断是否是ControllerBase if (typeDef.BaseType.Kind == HandleKind.TypeReference) { var baseTypeRef = metadataReader.GetTypeReference((TypeReferenceHandle)typeDef.BaseType); var baseTypeName = metadataReader.GetString(baseTypeRef.Name); if (baseTypeName is "ControllerBase" or "Controller") { isController = true; } } if (!isController) continue; Console.WriteLine($"找到控制器:{namespaceName}.{typeName}"); // 遍历控制器的所有公共方法 foreach (var methodDefHandle in typeDef.GetMethods()) { var methodDef = metadataReader.GetMethodDefinition(methodDefHandle); // 只取公共实例方法 if (methodDef.Attributes.HasFlag(MethodAttributes.Public) && !methodDef.Attributes.HasFlag(MethodAttributes.Static)) { var methodName = metadataReader.GetString(methodDef.Name); Console.WriteLine($" 方法:{methodName}"); } } }
这种方式完全不需要依赖目标WebApi的任何运行时程序集,不会出现缺失dll的报错,兼容性覆盖.NET Core 3.1到.NET 8的所有版本。
内容的提问来源于stack exchange,提问作者Adam Wojnar
相关产品推荐
相关产品推荐

