在Agile.NET里,很多人说的白名单,并不是单独一张名单文件,而是把不能改名、不能被误混淆的类型和成员提前排除出去。官方文档里对这件事的口径很清楚,符号重命名带来的异常,常见根源就是反射依赖;工具会自动识别一部分,但识别不到的部分,需要你自己补exclusions,或者直接在代码里用ObfuscationAttribute声明放行。
一、Agile.NET白名单怎么做
做白名单时,不要一上来就把整批命名空间全部排除。更稳的做法,是先把运行时真正依赖名字的对象找出来,再按类型、成员、程序集三层往里收,这样既能保住兼容性,也不会把保护强度一下放空。
1、先把默认边界看清
Agile.NET的声明式混淆文档说明,默认更偏向处理程序集内部成员,而符号重命名文档又说明,公共成员默认不会参与跨程序集重命名,除非你主动启用cross assembly obfuscation。所以白名单第一步不是把所有public再抄一遍,而是补那些虽然能编译通过、但运行时会被动态访问的对象。
2、先从exclusions入口补排除
官方文档明确给了额外exclusions的做法,适合处理工具自动识别不到的依赖。像插件入口、配置绑定类、通过字符串找成员的工具类、供脚本调用的公开方法,这些都更适合先从这里补白名单。
3、再把稳定规则回写到代码属性
如果你不想把规则只留在工具界面里,可以直接用System.Reflection.ObfuscationAttribute。Agile.NET官方的声明式混淆文档说明,这个属性支持用Exclude控制排除,用ApplyToMembers控制规则是否继续作用到成员,适合做长期可维护的放行规则。
4、跨程序集场景把相关程序集一起纳入
官方文档提醒,启用cross assembly obfuscation时,软件相关的程序集都应加入工程,即使其中一部分并不准备做保护。否则一个程序集里的名字变了,另一个还按旧名字引用,运行期就容易出现找不到类型或成员的情况。
二、Agile.NET对反射与序列化如何放行
反射和序列化最麻烦的地方,在于编译阶段往往没有明显提示,问题通常要到运行时才暴露。所以放行时不能只看有没有报错,而要先判断这段逻辑到底依赖的是类型名、成员名,还是外部数据契约。
1、反射先保住会被按名字查找的对象
Agile.NET官方已经明确说明,符号重命名引发的异常多半和reflection API有关。只要代码里存在Type.GetType、GetMethod、GetProperty、按约定名称加载插件、按字符串找成员这些写法,就不要只依赖自动识别,应该把相关类型或成员明确列入排除。
2、类型和成员分层放行
遇到某个类型整体要被反射访问时,可以先在类型级别做排除;如果只是少数入口方法、属性或字段会被外部按名访问,就只放行这些成员。用ObfuscationAttribute时,Exclude和ApplyToMembers正好可以把这两层拆开,避免整类全部失去保护。
3、XmlSerializer场景先保公共字段和可读写属性
微软文档说明,XML serialization默认序列化对象的public fields和public read/write properties。也就是说,如果你的XML输入输出依赖这些成员的公开名字,它们一旦被改名,序列化和反序列化的结果就可能对不上。
4、需要固定XML元素名时用序列化特性
微软文档说明,XmlElementAttribute可以作用在public fields或public read/write properties上,用来控制元素名称和其他XML特征。实际落地时,如果外部XML格式已经定死,就不要把兼容完全押在成员原名上,而是先用序列化特性把对外名字固定住,再决定内部成员是否允许混淆。
5、DataContract场景优先固定DataMember名称
微软文档写得很清楚,DataMemberAttribute默认使用CLR成员名作为数据成员名,而Name属性可以覆盖这个默认值。对于需要长期兼容的接口、缓存或历史数据,更稳的做法是先把Name固定下来,这样后面即使内部字段或属性调整,外部契约也不会跟着漂。
三、Agile.NET排除规则怎么固定
白名单真正难的不是第一次配出来,而是后面版本迭代时还能一直保持稳定。把排除规则固定成一套能复用的做法,比每次出了运行时异常再回头补救省事得多。
1、先列运行时依赖清单
把反射调用点、XML序列化对象、DataContract对象、插件入口、配置绑定类先列出来,再决定哪些走工具exclusions,哪些走代码属性。这样白名单是围着真实依赖收口,不是凭感觉大面积放行。
2、界面排除和代码属性配合使用
临时验证时可以先在工具里补exclusions,确认程序跑通后,再把稳定规则回写到ObfuscationAttribute。这样既方便快速试错,也能把最终规则跟着源码一起走,后面换人接手时不容易丢。
3、每次改规则后都测受保护版本
真正要验证的不是原始程序集,而是Agile.NET处理后的输出物。反射加载、XML读写、DataContract序列化、插件发现这些路径,都要在受保护版本上重新走一遍,只有这样才能确认白名单有没有真的放到位。这个流程是根据Agile.NET对重命名异常来源和微软对序列化默认规则的说明整理出来的。
4、能固定契约名时就别把兼容押在成员原名上
XML场景可以用XmlElementAttribute控制元素名,DataContract场景可以用DataMemberAttribute.Name固定数据成员名。把外部契约提前锁住,后面内部成员如何调整,就不会那么容易直接影响已有数据和对外接口。
总结
Agile.NET白名单怎么做Agile.NET对反射与序列化如何放行,核心不是去找一个单独叫白名单的按钮,而是把exclusions和ObfuscationAttribute两套能力配合起来。反射场景优先保名字,XML和DataContract场景优先保外部契约,再把这些规则固定到工程和代码里,后面的保护强度与运行兼容性才更容易一起稳住。