C# Telerik报表反序列化加载程序集报错StartIndex cannot be less than zero
排查方向
- 优先定位自定义程序集解析逻辑的bug:异常堆栈中
?A0x6aa5279c.domain_AssemblyResolve是项目中自行注册的AppDomain.AssemblyResolve事件处理方法,抛出ArgumentOutOfRangeException的根因是该方法内调用String.Substring时传入了小于0的起始索引,和Telerik报表序列化逻辑本身无关。仅切换数据库连接就触发异常,说明连接第二个数据库的执行链路中,这个存在bug的解析委托被注册,或者委托内的判断逻辑走到了出错分支;连接第一个数据库时该委托未生效,或未命中出错分支。 - 排查数据库配置触发的逻辑差异:全局搜索代码中所有
AppDomain.CurrentDomain.AssemblyResolve +=的注册点,逐一核对处理方法中的字符串处理逻辑:这类Substring报错几乎都是因为代码用IndexOf查找程序集名称的分隔符时,未判断返回值是否为-1,直接将-1作为起始索引传入Substring。切换数据库连接时,大概率触发了某个名称不符合预期格式的程序集加载请求,刚好命中这个bug分支。 - 核对Telerik程序集加载逻辑:
Telerik.Reporting.Design是设计时专用程序集,运行时不需要部署,正常报表反序列化不应该触发该程序集的加载。出现该加载请求,说明反序列化过程中尝试解析设计时专属的类型或属性转换器,才会走到自定义程序集解析逻辑触发报错。
解决方案
- 修复自定义程序集解析逻辑的边界判断:所有AssemblyResolve事件处理方法中,涉及字符串截取的逻辑必须先做边界校验,
IndexOf返回值小于0时直接返回null,终止后续解析逻辑,参考修复代码:
private Assembly CustomAssemblyResolve(object sender, ResolveEventArgs args) { string assemblyFullName = args.Name; int nameSplitIndex = assemblyFullName.IndexOf(','); // 新增边界判断,避免无效截取 if (nameSplitIndex < 0) { return null; } string assemblyShortName = assemblyFullName.Substring(0, nameSplitIndex); // 保留原有程序集查找、加载逻辑 }
- 清理报表XML中的无效设计时节点:检查存储的报表XML内容,删除所有引用
Telerik.Reporting.Design命名空间下类型、设计时专属属性/转换器的节点,从根源避免运行时加载设计时程序集的无效请求。 - 增加程序集加载诊断日志:在所有AssemblyResolve处理方法入口添加日志,记录待解析的程序集全名、触发解析的调用堆栈,可快速定位切换数据库时具体加载了什么模块触发了bug,以及是哪段代码注册了有问题的解析委托。
内容的提问来源于stack exchange,提问作者Ihor Pasieka
相关产品推荐
相关产品推荐

