.NET Core Web API部署IIS后程序集名变更 反射获取控制器方法失败
问题背景
- 运行环境:Visual Studio 2019,基于.NET Core开发Web API项目,采用Repository模式实现架构,需求为通过反射读取控制器内的所有方法与参数。
- 原有仓储层反射实现代码:
var method = MethodBase.GetCurrentMethod(); _log4net.Info("Assembly Name : " + Assembly.GetCallingAssembly().FullName); _log4net.Info("Method Name : " + method.Name); _log4net.Info("Repository Name :" + method.ReflectedType.FullName); var result = ((System.Reflection.TypeInfo)Assembly.GetCallingAssembly().GetTypes().Where(type => type.FullName.Contains("AsmeController")).FirstOrDefault()).DeclaredMethods; _log4net.Info(result);
- 异常现象:
- Debug调试模式下代码运行符合预期,可正常返回方法信息列表,日志显示对应业务程序集为
Demo.dll - Release模式发布部署到IIS后代码运行异常返回null;经日志排查,部署后通过
Assembly.GetCallingAssembly()获取到的程序集名称从Demo.dll变为Anonymously Hosted DynamicMethods Assembly,无法匹配到AsmeController类型,最终反射获取DeclaredMethods失败。
- Debug调试模式下代码运行符合预期,可正常返回方法信息列表,日志显示对应业务程序集为
可行解决建议
核心触发原因:Release模式下.NET Core JIT会做方法内联编译优化,同时代码中使用的LINQ Where查询会生成动态匿名方法,调用栈不再指向原始业务程序集,因此GetCallingAssembly()会拿到动态生成的匿名程序集,而非预期的Demo.dll
- 优先采用直接绑定目标类型所属程序集的方案,稳定性最高,完全不受编译优化、动态方法生成影响。不要依赖调用栈判断程序集归属,示例代码如下:
// 直接通过已知控制器类型获取其所在的业务程序集,避免调用栈变动导致的定位错误 var businessAssembly = typeof(AsmeController).Assembly; var targetController = businessAssembly.GetTypes() .FirstOrDefault(type => type.FullName != null && type.FullName.Contains("AsmeController")); if (targetController != null) { var result = targetController.GetTypeInfo().DeclaredMethods; _log4net.Info(result); }
- 如果不希望硬编码绑定具体控制器类型,可以遍历当前应用域加载的所有程序集,过滤掉动态程序集、系统框架程序集后再匹配目标控制器,示例代码如下:
var targetController = AppDomain.CurrentDomain.GetAssemblies() // 过滤动态生成的匿名程序集、.NET系统类库、微软官方框架类库 .Where(asm => !asm.IsDynamic && !asm.FullName.StartsWith("System.") && !asm.FullName.StartsWith("Microsoft.")) .SelectMany(asm => asm.GetTypes()) .FirstOrDefault(type => type.FullName != null && type.FullName.Contains("AsmeController")); if (targetController != null) { var result = targetController.GetTypeInfo().DeclaredMethods; _log4net.Info(result); }
- 不推荐的临时方案:关闭项目编译优化。右键对应项目→选择「属性」→进入「生成」选项卡,取消勾选「优化代码」,发布部署时同样关闭优化配置。该方案会损失部分程序运行性能,仅适合临时调试使用。
- 编码优化提示:原有代码未对
FirstOrDefault()的匹配结果做空值判断,一旦类型匹配失败直接做类型强转就会触发空引用异常,反射逻辑必须增加空值校验,避免线上服务报错。
内容的提问来源于stack exchange,提问作者Surendra
相关产品推荐
相关产品推荐

