[绝对原创]从VS2003(.net1.1)升级到vs2005(.net2.0)全程跟踪记录
上一篇blog中提到最近正忙着项目升级到.net2.0,这两天差不多告一段落,就等着提交测试了。
从现在开始,我将逐步回顾下升级过程中的来龙去脉,并重点追击升级中遇到的问题及解决方法。
备注:为了方便阅读,我将不断补充本文内容,不再开辟新的文章,并在评论中注释最新增加的内容。感兴趣的朋友可以订阅本文。
[项目背景介绍]
本文要升级的项目是我公司目前的一个电子商务门户站点,系统极其复杂,2004年做成这个系统,几年来不断变迁,代码日积月累,产生了许多无用或重复性的代码,光UI版面就已经更新过不下5个版本。我从去年夏天来到这个公司,中间就经历过一次惨痛的界面升级,说是界面升级,其实.net版本却不升级,依旧是.net1.1,仅仅是UI层的全部重做,可想而知,在不动原有逻辑的前提下,这个界面升级过程有多么得艰辛,何况还是使用VS2003,所以代码中不知不觉地“滋生”了数不尽的“<FONT face="宋体"></FONT>”这样的垃圾代码,追求完美的我,极其讨厌这类东西的存在。虽然最早从VS2003的Beta2开始用起,我曾经也用过1年的VS2005,如今又用回了VS2003,这种落差很是痛苦,我曾经和同事开玩笑说“再不升级的话,下次招聘的新人,都不会用vs2003和.net1.1写代码了”。
说完了项目大概介绍,再说说项目的业务情况,由于涉及到公司机密,不便太具体。我们的站点涉及人员有5个业务人员、1个flash设计人员、两个开发人员,以及一个共用的DBA,还有若干共用的美工设计人员和共用的测试人员,我就是两个开发人员之一。说起DBA,也很无奈,在我来到这边的将近一年时间里,来了2个DBA,走了两个DBA,现在存储过程的编写及数据表的建立都是我们开发人员自己来完成,唯一的DBA只负责数据库层面的发布。几个业务人员在一个经理的带领下,不断地“折磨”我们,由于平时活动很多以及经常和公司其他项目合作,必须不断地谈需求、沟通,所以平时用于开发的时间实际上不到整个活动周期的1/2。由于活动安排得很紧凑,软件开发流程中能省得步骤都省去了,设计、评审等都只在美好的幻想中存在过,大多是头脑风暴式的开发,专业一点的说法应该是敏捷编程或极限编程吧,当然我们这样的开发过程绝对不能和敏捷编程或极限编程相提并论,这里只是一个形象得比喻,对敏捷编程、极限编程,我只了解大概意思,最近刚下了《敏捷软件开发:原则、模式与实践》这本书的电子稿(17.9m),还没来得及看。需要的朋友可以给我留言。说着说着就跑题了,说这么多都是为了升级做铺垫,我实在忍不住了,特别是对项目的现状很烦恼。既然无法改变自己,那就改变自己主宰的事物吧。
升级开始!但升级也面临着很大的挑战,不光是升级要解决的数不尽未知问题,更是由于业务人员可不会给我空闲时间来做这事,上头都是由指标的,我也理解,我自己也是和他们绑定在一起,考核同一个指标。所以升级过程中,我必须不断把最新的更新内容加到新版本中,升级的时间跨度越长,不断更新的内容就越多,升级的风险就越大。
五一只有三天,还没休息够,这周又连着上6天班,一直把今天当作周末,一直盼望着晚上可以稍微晚点睡觉以及明天的美美一觉,可惜一切只是幻想,直接导致了下午不想做事。
[升级准备]
说实话,以及收藏过很多.net1.1升级到.net2.0的文章,都是2年前的事,当初也是想将来总用得到吧,没想到真被我遇上了。大概地看下别人的介绍,毕竟具体情况具体分析,并没有很大的参照性,倒是给我的心理无形中增加了很大压力。
言归正传,升级前,我做了如下准备:(假设原web Application是http://localhost/ProjectWeb。)
1、确保VS2005已经打上sp1补丁。
2、准备好纸和笔,随时记录升级过程中的问题和操作步骤。
3、拷贝一份最新的代码到另一个目录(假设为NewProject,其中web项目的文件夹为ProjectWeb),所有文件全部取消“只读”属性。
4、给新目录中的web项目(即:NewProject中的ProjectWeb文件夹)指定一个新的虚拟目录,比如为http://localhost/NewProjectWeb,修改web项目的webinfo文件中的URL地址为http://localhost/NewProjectWeb/,相应的web项目中的*.csproj和*.vspscc中的URL地址都改为http://localhost/NewProjectWeb。
5、用vs2003打开拷贝的那份代码(下文操作对象都是这份拷贝的代码),先断开源代码连接并移除源代码管理信息,然后再拷贝一份移除源代码管理信息的“干干净净”的代码,事后证明这个貌似多余的一个步骤绝对是没错的。
6、再用VS2005打开第5步之后的没有源代码管理信息的“干干净净”的项目解决方案,提示转化,确定,不用备份(因为已经有备份了),直到转化完毕,好,问题来了。
[问题列表及解决方法]
1、Math.Floor()函数出错;2.0中,该函数接收两种类型的参数decimal和double,与1.1中有差别,所以这个小问题在参数前直接加上Convert.ToDecimal()即可。
2、在1.1中,某个页面Test.aspx的codebehind文件Test.aspx.cs,类名Test,如果在某个地方实例化Test的对象:
Test test = new Test();//注意实例名test
当从1.1转化到2.0的时候,会自动把Test作为一个抽象类,放在App_Code中Migrated文件夹下,然后Test.aspx.cs中的类名改为Migrated_Test,同时继承自Test这个抽象类。可想而知,原先代码内部实例化Test的部分就会出错。另外,转化生成的抽象类Test中包含几个抽象方法和属性,这些属性和方法都没有实现,并且这些属性名和方法名在原先未升级的代码中,都是被前面提到的实例化对象test所调用。test没有调用的那些属性和方法、字段都不会跑到这个抽象类中。
[解决方法]1)这类情况的解决方法,我的这样做的:把转化成的抽象类Test改为非抽象类TestProxy,然后其中的属性、方法等,把原先的代码拷贝过来,形成完整的一个类。
2)再把Test.aspx.cs中的类名Migrated_Test改为Test。
3)最后把前面实例化Test部分的代码Test test = new Test(); 改为 TestProxy test = new TestProxy();
3、这个问题就很普遍了,就是在绑定下拉框等控件过程中会遇到的情况。如果省市联动,一般都会使用两个DropDownList控件,用js脚本实现联动。很不幸的是,当转化之后,当你点击按钮post当前页面,会提示“回发或回调函数无效……”等一大串错误。如果大家不明白这个问题的描述,可以把“回发或回调函数无效”这几个字作为关键字,搜索下博客园,出来的结果会告诉你详细的事实。
[解决方法]还是以省市联动这个例子,首先把选择“市”这个下拉框改回html控件<select id="city" name="city" runat="server"></select>,别忘了其中的runat=server,不然在codefile中就引用不到这个控件,也就取不到选择的值。然后再CodeFile中,取省市的值的时候,用Request.Form[city.Name]即可。
(补充一句:这里的city.ClientID和city.Name的值是一样的,如果是在用户控件(假设ID为userControl)中,那两者的值就不一样了,ClientID的值是“userControl_city”,而Name的值是“userControl:city”,此时使用city.Name才能取到值,总之,使用city.Name取值就可以了。)具体代码在公司,细节描述如果有差错,请见谅,明天我核对再发。
4、这个问题估计不是什么问题……如果页面声明部分加上了AutoEventWireup="false",在1.1中,CodeBehide中的Page_Load()是可以被执行的,但是在2.0种,很偶然地,我发现页面声明部分加上AutoEventWireup="false"的CodeFile中的 Page_Load()就不会被执行。但OnLoad()是可以执行的,难怪以前见到有人从来不用Page_Load()而使用OnLoad()。偶然还是?至少我发现的几个页面都是这样。在查看了AutoEventWireup的相关知识之后,我大概可以这么理解:
[升级过程中的建议和推荐做法]
这里随便说说,在升级过程中我是如何保持新旧版本的同步问题吧。我们有两个开发人员,在升级的这一段时间里,我专门来做升级的事,偶尔也开发些属于我之前开发过的模块,另一个人负责新活动的开发任务。这就存在一个版本的同步更新问题。我是这么做的:
1、通过VSS来监视哪些文件修改了,每天下班前2个小时专门来同步新旧版本。
2、如果是类库的代码有更新,则直接从VSS来获得最新版本。
3、如果是页面的更新,则通过VSS的Show Difference来手动一点点更新,这个过程比较痛苦。
4、有耐心做,要够细心,也要有信心做好。
ps:貌似不发到首页都没访问量啊,厚着脸皮贴上首页吧,看到我写了这么多的份上……
从现在开始,我将逐步回顾下升级过程中的来龙去脉,并重点追击升级中遇到的问题及解决方法。
备注:为了方便阅读,我将不断补充本文内容,不再开辟新的文章,并在评论中注释最新增加的内容。感兴趣的朋友可以订阅本文。
[项目背景介绍]
本文要升级的项目是我公司目前的一个电子商务门户站点,系统极其复杂,2004年做成这个系统,几年来不断变迁,代码日积月累,产生了许多无用或重复性的代码,光UI版面就已经更新过不下5个版本。我从去年夏天来到这个公司,中间就经历过一次惨痛的界面升级,说是界面升级,其实.net版本却不升级,依旧是.net1.1,仅仅是UI层的全部重做,可想而知,在不动原有逻辑的前提下,这个界面升级过程有多么得艰辛,何况还是使用VS2003,所以代码中不知不觉地“滋生”了数不尽的“<FONT face="宋体"></FONT>”这样的垃圾代码,追求完美的我,极其讨厌这类东西的存在。虽然最早从VS2003的Beta2开始用起,我曾经也用过1年的VS2005,如今又用回了VS2003,这种落差很是痛苦,我曾经和同事开玩笑说“再不升级的话,下次招聘的新人,都不会用vs2003和.net1.1写代码了”。
说完了项目大概介绍,再说说项目的业务情况,由于涉及到公司机密,不便太具体。我们的站点涉及人员有5个业务人员、1个flash设计人员、两个开发人员,以及一个共用的DBA,还有若干共用的美工设计人员和共用的测试人员,我就是两个开发人员之一。说起DBA,也很无奈,在我来到这边的将近一年时间里,来了2个DBA,走了两个DBA,现在存储过程的编写及数据表的建立都是我们开发人员自己来完成,唯一的DBA只负责数据库层面的发布。几个业务人员在一个经理的带领下,不断地“折磨”我们,由于平时活动很多以及经常和公司其他项目合作,必须不断地谈需求、沟通,所以平时用于开发的时间实际上不到整个活动周期的1/2。由于活动安排得很紧凑,软件开发流程中能省得步骤都省去了,设计、评审等都只在美好的幻想中存在过,大多是头脑风暴式的开发,专业一点的说法应该是敏捷编程或极限编程吧,当然我们这样的开发过程绝对不能和敏捷编程或极限编程相提并论,这里只是一个形象得比喻,对敏捷编程、极限编程,我只了解大概意思,最近刚下了《敏捷软件开发:原则、模式与实践》这本书的电子稿(17.9m),还没来得及看。需要的朋友可以给我留言。说着说着就跑题了,说这么多都是为了升级做铺垫,我实在忍不住了,特别是对项目的现状很烦恼。既然无法改变自己,那就改变自己主宰的事物吧。
升级开始!但升级也面临着很大的挑战,不光是升级要解决的数不尽未知问题,更是由于业务人员可不会给我空闲时间来做这事,上头都是由指标的,我也理解,我自己也是和他们绑定在一起,考核同一个指标。所以升级过程中,我必须不断把最新的更新内容加到新版本中,升级的时间跨度越长,不断更新的内容就越多,升级的风险就越大。
五一只有三天,还没休息够,这周又连着上6天班,一直把今天当作周末,一直盼望着晚上可以稍微晚点睡觉以及明天的美美一觉,可惜一切只是幻想,直接导致了下午不想做事。
[升级准备]
说实话,以及收藏过很多.net1.1升级到.net2.0的文章,都是2年前的事,当初也是想将来总用得到吧,没想到真被我遇上了。大概地看下别人的介绍,毕竟具体情况具体分析,并没有很大的参照性,倒是给我的心理无形中增加了很大压力。
言归正传,升级前,我做了如下准备:(假设原web Application是http://localhost/ProjectWeb。)
1、确保VS2005已经打上sp1补丁。
2、准备好纸和笔,随时记录升级过程中的问题和操作步骤。
3、拷贝一份最新的代码到另一个目录(假设为NewProject,其中web项目的文件夹为ProjectWeb),所有文件全部取消“只读”属性。
4、给新目录中的web项目(即:NewProject中的ProjectWeb文件夹)指定一个新的虚拟目录,比如为http://localhost/NewProjectWeb,修改web项目的webinfo文件中的URL地址为http://localhost/NewProjectWeb/,相应的web项目中的*.csproj和*.vspscc中的URL地址都改为http://localhost/NewProjectWeb。
5、用vs2003打开拷贝的那份代码(下文操作对象都是这份拷贝的代码),先断开源代码连接并移除源代码管理信息,然后再拷贝一份移除源代码管理信息的“干干净净”的代码,事后证明这个貌似多余的一个步骤绝对是没错的。
6、再用VS2005打开第5步之后的没有源代码管理信息的“干干净净”的项目解决方案,提示转化,确定,不用备份(因为已经有备份了),直到转化完毕,好,问题来了。
[问题列表及解决方法]
1、Math.Floor()函数出错;2.0中,该函数接收两种类型的参数decimal和double,与1.1中有差别,所以这个小问题在参数前直接加上Convert.ToDecimal()即可。
2、在1.1中,某个页面Test.aspx的codebehind文件Test.aspx.cs,类名Test,如果在某个地方实例化Test的对象:
Test test = new Test();//注意实例名test
当从1.1转化到2.0的时候,会自动把Test作为一个抽象类,放在App_Code中Migrated文件夹下,然后Test.aspx.cs中的类名改为Migrated_Test,同时继承自Test这个抽象类。可想而知,原先代码内部实例化Test的部分就会出错。另外,转化生成的抽象类Test中包含几个抽象方法和属性,这些属性和方法都没有实现,并且这些属性名和方法名在原先未升级的代码中,都是被前面提到的实例化对象test所调用。test没有调用的那些属性和方法、字段都不会跑到这个抽象类中。
[解决方法]1)这类情况的解决方法,我的这样做的:把转化成的抽象类Test改为非抽象类TestProxy,然后其中的属性、方法等,把原先的代码拷贝过来,形成完整的一个类。
2)再把Test.aspx.cs中的类名Migrated_Test改为Test。
3)最后把前面实例化Test部分的代码Test test = new Test(); 改为 TestProxy test = new TestProxy();
3、这个问题就很普遍了,就是在绑定下拉框等控件过程中会遇到的情况。如果省市联动,一般都会使用两个DropDownList控件,用js脚本实现联动。很不幸的是,当转化之后,当你点击按钮post当前页面,会提示“回发或回调函数无效……”等一大串错误。如果大家不明白这个问题的描述,可以把“回发或回调函数无效”这几个字作为关键字,搜索下博客园,出来的结果会告诉你详细的事实。
[解决方法]还是以省市联动这个例子,首先把选择“市”这个下拉框改回html控件<select id="city" name="city" runat="server"></select>,别忘了其中的runat=server,不然在codefile中就引用不到这个控件,也就取不到选择的值。然后再CodeFile中,取省市的值的时候,用Request.Form[city.Name]即可。
(补充一句:这里的city.ClientID和city.Name的值是一样的,如果是在用户控件(假设ID为userControl)中,那两者的值就不一样了,ClientID的值是“userControl_city”,而Name的值是“userControl:city”,此时使用city.Name才能取到值,总之,使用city.Name取值就可以了。)具体代码在公司,细节描述如果有差错,请见谅,明天我核对再发。
4、这个问题估计不是什么问题……如果页面声明部分加上了AutoEventWireup="false",在1.1中,CodeBehide中的Page_Load()是可以被执行的,但是在2.0种,很偶然地,我发现页面声明部分加上AutoEventWireup="false"的CodeFile中的 Page_Load()就不会被执行。但OnLoad()是可以执行的,难怪以前见到有人从来不用Page_Load()而使用OnLoad()。偶然还是?至少我发现的几个页面都是这样。在查看了AutoEventWireup的相关知识之后,我大概可以这么理解:
[升级过程中的建议和推荐做法]
这里随便说说,在升级过程中我是如何保持新旧版本的同步问题吧。我们有两个开发人员,在升级的这一段时间里,我专门来做升级的事,偶尔也开发些属于我之前开发过的模块,另一个人负责新活动的开发任务。这就存在一个版本的同步更新问题。我是这么做的:
1、通过VSS来监视哪些文件修改了,每天下班前2个小时专门来同步新旧版本。
2、如果是类库的代码有更新,则直接从VSS来获得最新版本。
3、如果是页面的更新,则通过VSS的Show Difference来手动一点点更新,这个过程比较痛苦。
4、有耐心做,要够细心,也要有信心做好。
ps:貌似不发到首页都没访问量啊,厚着脸皮贴上首页吧,看到我写了这么多的份上……