《Windows 用户态程序高效排错》市场价元 特价元 购买>> 本可以做得更好SharePoint中文界面变英文 问题描述 Windows SharePoint Portal 是运行在NET Framework上的一个web应用程序管理员可以设定使用英文界面或者中文界面某天一个客户抱怨SharePoint无法显示中文界面所有的页面都用英文显示经过仔细观察发现下面的现象: 管理员的设定值是中文界面 该程序在过去的一年中都运行正常 大多数情况下中文界面工作正常 偶然有几次中文界面会变成英文界面 变成英文界面后过一段时间后会自动变回中文界面 变成英文界面后如果重新启动IIS 有可能解决问题 排错步骤 经过观察发现客户的安装和配置是没有问题的大致调试后发现: 客户程序工作线程的UI Culture的确是zhcn 跟客户的设定一致 界面显示资源是通过ResourceManagerGetString系统方法来加载的 ResourceManagerGetString http://msdnmicrosoftcom/enus/systemresourcesresourcemanagergetstringaspx 该客户的中文资源卫星文件安装正确 根据这个信息GetString应该返回对应的中文资源但是在问题发生的时候返回的却是英文资源所以需要解释的是这个NET系统方法为何表现异常面临的难点是 无法简单重现问题需要反复重新启动IIS多次后问题才会偶然发生 问题只有在客户机器上才能重现需要远程调试操作起来不是很方便 由于出问题的代码是NET Framework的函数不是客户的代码没办法用第个例子的方法来添加log分析 当时欧洲很多客户也有类似问题发生比如西班牙语的站点变成了英语日本更是严重有十几个站点都有这个问题但是几个星期来一直都没有找到问题的根源 由于问题的线索是GetString方法的异常表现所以排错计划也非常直接跟蹤GetString的执行过程在做远程调试以前首先在本地跟蹤GetString的执行过程来理解逻辑大致的逻辑是 资源符号从卫星加载起来后会放到内存的HashTable中 GetString检查HashTable中是否有请求的资源如果有跳到第步 如果没有GetString会让ResourceManager根据当前线程的UI Culture寻找对应卫星目录来加载 ResourceManager加载卫星Assembly到内存同时把所有的资源符号都写入HashTable GetString返回这个HashTable中对应的资源 如果有问题发生比如ResourceManager没有找到对应的卫星目录或者资源文件不存在就用中立语言(英语)资源代替 一旦HashTable填充完成GetString的后继执行就不需要使用ResourceManager了直接返回HashTable的内容 根据上面的逻辑客户那里的问题很可能是ResourceManager没有找到资源文件于是就用英语初始化HashTable根据这个信息决定用Filemon来检视资源文件的访问可惜的是Filemon的结果表明每次对资源文件的访问都是成功的同时再次检查了资源文件的安装也没有发现异常 走投无路的时候只有通过远程调试来检查了跟客户交流后客户同意在把晚上点到早上点的时间段留给我们来排错为了排除干扰用下面的步骤来检查 在IIS上限制只有测试用客户端IP才能访问 把IIS和ASPNET的超时时间都设定到无限长 每次调试前重新启动IIS 在客户端刷新一次页面然后在调试器中检查GetString和ResourceManager的执行过程 限制IP的目的是为了控制重现问题的时机防止有其他用户来访问页面重新启动IIS是必须的因为要观察HashTable的初始化过程设定超时时间是为了防止超时异常干扰调试在连续几天的努力后发现下面的线索 加载卫星文件的时候失败了 加载过程中有两次first chance CLR exception 问题发生的时候执行了一些异常的codepath这个codepath上很多函数的名字比较新颖在本地测试的时候没看到类似的函数 根据上面的结果重新在本地检查对应的代码然后结合wt命令和异常发生的时机抓取某些codepath的执行过程分析后发现一个比较重要的线索客户那里部署了NET Framework SP一些SP中新加入的codepath被执行到了 经过最后的整理和分析发现了问题是这样的在NET Framework 上ResourceManager判断当前线程的UI Culture后就开始寻找对应的卫星文件但是SP中添加了某一个额外的配置选项使得寻找的过程可以通过webconfig来配置由于 webconfig配置文件很重要普通的web用户是没有权限访问的在访问webconfig过程中一旦发生了Access Denied就会导致CLR exception异常发生后ResourceManager认为某些地方出了问题于是ResourceManager停止加载卫星文件用中立资源代替于是英文就代替了中文 换句话说设计者没有考虑到web程序中没有权限去访问CLR程序配置文件(web程序中是webconfig)的情况是很常见的这种情况没有被特殊处理因而导致了问题 在客户重新启动IIS后如果程序第一个使用者权限比较高能够访问webconfig的话中文资源就可以加载起来如果第一个使用者权限比较低问题就发生了而且会一直保留到下一次IIS重新启动再次加载资源的时候暂时的解决方法是把webconfig设定为Everyone Access Allow这个workaround在一个星期内迅速帮助了全球范围内很多SPS站点的显示正常起来 当然修改webconfig的权限是非常危险的所以申请一个hotfix才是最终的解决方案 FIX: Your application cannot load resources from a satellite assembly if the impersonated user account does not have permissions to access the application config file in the NET Framework Service Pack http://supportmicrosoftcom/?id= 错过的线索 如果仔细分析这个案例的解决过程 会发现排错初期距离胜利就只有一步之遥已经想到了用Filemon去观察卫星文件的访问情况但是就没想到用Filemon观察里面是否有Access Denied事后拿出当时的Filemon结果查找Access Denied一共发现了几处同时当观察到该问题以前一直没有现在突然像洪水一样全球泛滥时就应该意识到最近一段时间发布的一些重要补丁很可疑 所以如果想做得更好一点不在于使用了多少工具用了多么深奥的调试技术而在于能够比经验主义多想到一点什么开拓一下思路可以很简单地四两拔千斤 这一章不在于演示出一套分析问题的模版而是想说明解决问题的核心武器是思考知识和工具只是辅助在遇上问题的时候能够多想一分钟再动手本章的目的就达到了 |