zoukankan      html  css  js  c++  java
  • 升级.Net 4.0遇到的两个问题

    引言

    想升级到.Net 4.0已经很有一段时间了,本来是应该把各个工程文件都升级的,但由于种种原因,一直没有太合适的时机。考虑.Net 4.0可以做到版本想下兼容,因此在近期采用保持dll不变,而仅仅将程序运行环境升级到.Net 4.0的策略进行了一次升级工作。我们的程序为一个Web应用,在升级过程中遇到了两个比较有意思的问题,特予以记录。

    主要的升级工作

    对于Web应用,主要的升级工作其实就是手工更改web.config文件,主要参考了以下文档:

       How to: Upgrade an ASP.NET Web Application to ASP.NET 4

     

    另外,为httpRuntime节增加了一个requestValidationMode属性:

    clip_image002

    否则在操作页面时会出现下面的错误:

    clip_image004

     

    问题1:ClientIDModel

    修改web.config后,在32位环境下已基本可运行。但部分功能节点出现问题,表现为弹出窗口关闭后,主界面并未按预期刷新。

     

    通过Visual Studio调试器跟踪,发现是服务端找不到btnFind控件,所以没有触发btnFind_Click事件。服务端控件创建没有问题,但客户端传递的EventTarget是M$P1$BtnFind,而正确的值应该是u$M$P1$BtnFind。

    clip_image006

    服务端控件中,CachedUniqueID是期望的,CachedPredictableID则输出了不正确的ID。原因是.net使用了Predictable方式进行ID输出:

    clip_image008

    Predictable是4.0提供的一种优化的ID生成算法,也是默认的配置。将ClientIDMode修改成 "AutoID",使用.Net 2.0的方式进行ID输出,问题解决:

    clip_image010

    问题2:64位环境下w3wp进程启动时崩溃

    解决问题1后,在32位环境下web应用一切正常。但在64位环境下,发现w3wp.exe启动时出现Crash现象,IIS在自动连续尝试3次后停止,而IE客户端指示无法显示该网页:

    clip_image012

    注:即便是64位环境,如果将AppPool配置为32位模式也没有问题。

     

    收集Dump文件,发现是由于ExecutionEngineException异常导致w3wp崩溃

    clip_image014

    调用栈指示最后的出错位置是在通过反射获取Assembly相关Attribute时:

    clip_image016

    查看相关代码,作用是查找AppDomain中加载的Assembly,如果有Assembly打上了AjaxFrameworkAssemblyAttribute标记,则将该Assembly作为DefaultAjaxFrameworkAssembly,否则使用系统自带的System.Web.Extensions程序集:

    clip_image018

    每个ScriptManager在创建时均会触发上述代码,通过两个静态变量_defaultAjaxFrameworkAssembly和_ajaxFrameworkAssemblyConfigChecked控制相关逻辑只触发1次。

     

    在了解了代码的大致逻辑后,解决问题的思路自然就是要查看究竟是在获取哪个Assmbly的CustomAttributes时引发了异常?但捕获的dump文件已无法确定assembly的详细信息。于是直接用Reflector Pro反编译生成CLR源码进行调试。调试时发现,尽管设置断点可以顺利命中,但各个变量的值却无法用调试器查看,原因是CLR代码已优化。

     

    换一个做法,把反编译得到的相关代码拷贝出来,单独放置到一个独立的.aspx页面文件中执行,顺利得到了异常信息:

    clip_image020

    引发问题的是一个FarPoint.CalcEngine.dll,将其从Portal\bin下删除后w3wp就可以正常启动了。FarPoint是一个第三方图形控件,其Target Runtime指示为.Net 1.0。但这并非问题所在,FarPoint有多个dll,均为.Net 1.0,但只有这个FarPoint.CalcEngine.dll会引发问题:

      clip_image022

    问题解法

    显然,每次通过手工排查的方式去查找引发异常的Assembly太累了,需要一种较为彻底的解决方案。选择的解决方案为通过反射技术将_defaultAjaxFrameworkAssembly强制赋值为true,以屏蔽掉查找DefaultAjaxFrameworkAssembly的逻辑

     

    具体做法是编辑网站的Global.asax文件,在Application_Start事件处理函数中加入如下两行代码:

       System.Reflection.FieldInfo fldInfo = typeof(System.Web.UI.ScriptManager).GetField("_ajaxFrameworkAssemblyConfigChecked",

          System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);

       fldInfo.SetValue(fldInfo.GetValue(null), true);

    至此问题圆满解决。

    问题探讨

    其实问题1并非真的问题,微软只是没有在升级Asp.net 4的文档中指明而已,但另外有一个同样来自微软的文档,已经详细描述了包括ClientIDModel在内的一些由.Net 4.0引发的变动问题:

       ASP.NET 4 Breaking Changes

     

    但问题2我认为是一个大问题,很难理解设计者的意图。难道是允许开发者替换默认的MS-Ajax框架?如果真是这样,那ScriptManager也会被替换掉啊,怎么可能保留MS-Ajax的ScriptManager,由其指向一个第三方的Ajax框架?另外,代码实现缺乏健壮性,至少应该加一个try..catch异常处理,避免程序崩溃。估计开发者没有考虑到会有Assembly导致出现致命异常的情况。

     

    这里还有一个疑问,就是为什么64位环境和32位环境会存在差异?用windbg的!Analyze –v命令对dump文件进行分析,最后的Native代码为调用clr!BlobToAttributeSet方法,触发的是一个访问违例异常(AccessViolationException):

      clip_image024

    从以上信息看,最后出错是因为访问了一个空指针。按理,32位的windows和64位的windows在虚拟空间的最底层都留了64K用于空指针检查,并无特别差异,何况这里是真正为0的空指针啊?

     

    用ILDasm查看FarPoint.CalcEngine.dll,推测Bug应该是由这个reqrefuse引用为空造成的

    clip_image026

    这是该dll与其它几个FarPoint dll最显著的一个不同之处。至于问题的准确答案,也只有能用CLR Native源码进行调试的微软程序员可以给我们解惑了。

  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    基于分布式锁解决定时任务重复问题
    基于Redis的Setnx实现分布式锁
    基于数据库悲观锁的分布式锁
    使用锁解决电商中的超卖
  • 原文地址:https://www.cnblogs.com/hbzhang/p/2288249.html
Copyright © 2011-2022 走看看