《Visual Studio.NET Tips and Tricks》第五章的翻译

 

第五章           其它.NET技巧

这章包含与.NET相关的技巧。它们中的大多数与VS.NET并没有关系。但是,我决定包含到这本书中,因为它们适用于大多数的VS.NET开发者。.NET亲手可能不熟悉这些技巧。

混淆你的.NET程序集

       当你编译.NET源代码时,这并不是被编译成机器码,而是编译成微软的中间语言(MISL)。在特定的机器上的.NET框架处理编译MISL代码成机器码的工作-叫做即时编译的过程。这说明MISL是个非常开放的格式。任何理解MISL的人都能探测,阅读和理解你的程序。

       因为你的代码并没有被编译成机器码,因此你的程序集非常容易被反编译-分析你的程序集并能中推断出你的源代码的过程。这个过程并不难,事实上,许多工具能高效地为你作这个工作:只要把你编译后的可执行的文件给工具,就会得到原始的C#VB.NET源代码。当然,所产生的源代码不同于你自己的,实际的源代码,但你确实能够阅读和理解的代码。

       为了补救这个问题,在编译代码后你需要混淆代码,混淆是改变你的源代码或中间语言代码,但并不改变整个程序的逻辑流程的过程。这涉及到对变量重命名,放几个无关的方法到一个重载的方法中,改变容易阅读的switch/case/if语句成难以阅读的goto语句等等。但是这些步骤并不能阻止反编译,只不过工具产生的源代码含义模糊,难于理解。

       VS.NET20032005本身带了第三方的混淆器叫做Dotfuscator。通过选择工具>Dotfuscator Community Edition能够运行它。

HTML代码改变后不用重新生成

       我看到Web开发者在调试过程中只因为编辑了应用的HTML部分就重新生成一个完整的Web应用。当你修改了一个.aspx文件的HTML部分时并不需要重新生成和重新开始Web应用。这包括改变Web控件的属性,即使它能非常显著地改变Web页面的输出。当你只是改变HTML时,简单地刷新浏览器并不用重新开始调试过程。变化就会立即生效。

在一个字符串通过一个字符或字符基迭代

       字符串在.NET中是非常奇异的变量类型。它们是引用类型的变量,即使它们的行为表现像值类型变量。虽然你能通过代码改变一个字符串的值,但它们仍然是不可变的(当你“改变”一个字符串时,一个新的字符串被创建)。

       关于字符串一个酷的事情就是它们经常行为表现像字符数组。这意味着你能使用简单的foreach循环通过单个字符迭代一个字符串。

       Foreach(char myChar in myString){…}

       同样,你能得到字符串中的第七个字符通过用方括号来索引它:

       char myChar=myString[6]

使用内连的字符串作为对象实例

       字符串似乎是更加深奥的,内边的字符串行为表现像对象实例。如果你一个字符串加上引号在你的编辑器中,保留在一个周期中,智能感知就会出现,允许你从同一个方法体内选择,就如同一个字符串变量一样:

       string prefixRemoved =myString.Substring(“INFORMATION”.Length)

在你的项目中增加app.config

       调用System.Configuration.ConfigurationSettings.AppSettings集合总是能够探测一个程序集的.config文件。对于Web应用,它是Web.config文件;对于Windows应用,这是MyWinodwsApp.exe.config文件。缺省状态下,VS.NET对于一个新的空Web应用会创建Web.config文件但是,对于Windows应用,你必须手工加这个文件。

       许多开发者创建一个文本文件以MyWindowsApp.exe.config命名并把它放在一个项目的输出目录。但是这是有问题的因为你必须作两次:一次对于Debug文件夹,一次对于Release文件夹。当你改变了输出程序集的名字时你也必须改变.config文件的名字。

       有一个更好的方法来管理.config文件。在你的项目上右击,从弹出的菜单上选择增加新的项目。在增加新的项目的对话框上,导航到当地项目项>工具文件夹,选择应用配置文件(对于VS.NET2005,简单地选择“app”项)。这会增加一个叫做App.config的文本文件到你的项目中(见图89)。

       注意:一些VS.NET安装在增加新项对话框上并不会显示应用配置文件。在这种情况下,你必须创建一个叫做App.config的文本文件并放到项目的根文件夹下。

 

89      增加一个应用配置文件

       关于配置文件的好的事情就是无论你什么时候生成项目,App.config文件会被拷贝到正确的文件夹下(DebugRelease,或你当前的可能的配置)适当地重命名(“MyWindowsApp.exe.config”)。

       注意:App.config只能应用于主程序集,并不能应用于类库DLLs

使用中间语言反编译器探视一个.NET程序集

       VS.NET安装过程中,你同样能选择安装.NET框架SDKSDK包含了许多有用的工具。其中一个就是中间语言反编译器(ildasm.exe),通常位于VS.NET的子目录中:

       VS.NET2002:C:\Program Files\Microsoft Visual Studio.NET\FrameworkSDK\Bin

       VS.NET2003: C:\Program Files\Microsoft Visual Studio.NET2003\SDK\v1.1\Bin

       VS.NET2005: C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

       中间语言反编译器允许你打开和探测一个.NET程序集(见图90)。你能看到类中所有的命名空间和类,并能读到微软的中间语言代码。读MSIL代码是非常有用的,如果代码有性能问题需要你调整你的应用时。

 

90      使用ILDASM探测一个.NET程序集

       ILDASM工具对于探测编译器生成给定的程序集时使用的.NET框架版本时也是有用的。看一个程序集的manifest段能看到它引用的系统程序集的版本。一个版本号1:0:5000:0意味着它是用.NET框架1.0编译的,一个版本号1:0:3300:0指示它是用1.1版本编译的。并不惊奇,.NET框架2.0有一个以“2:0开头的版本号。

使用Windows类查看器反射一个类

       在和ILDASM工具在.NET框架SDK中同样的目录中你将发现另一个有用的工具叫做Windows类查看器(WinCV.exe)。这个程序担当一个快速搜索任何定义在.NET框架中的.NET类功能。使用类的一部分名字来搜索一个类,会列出所有可能匹配的类。搜索是相当快的,通过敲入更多地的字母结果会自动更新缩减你的搜索。

       一旦你选择了一个类,你将会看到C++头文件一样的信息,包括所有的构造体,方法,属性,事件,和别的成员域(见图91)。

 

91      WinCV.exe显示一个类的所有成员域

       注意:VS.NET2005提供给你非常类似的东西,当使用类定义视图时。

运行aspnet_regiis修补一个IIS安装

       当安装VS.NETVS.NET框架SDK到一个你想用来开发Web应用新的机器上时,最好的规则就是首先安装IIS,因为.NET安装会安装和注册必需的ASP.NET ISAIP扩展DLL。如果你在安装了.NET后安装IISIIS将不会正确地和ASP.NET一块工作。

       代替重新安装.NET,你能使用一个非常有用的和.NET框架SDK捆绑在一起的工具,在.NET框架目录(类型的是C:\Windows\Microsoft.NET\Framework\v1.1.4322,或你正在运行的.NET的版本号)有一个小的命令行工具,叫做aspnet-regiis.exe

       像下面一样运行这个工具能够重新安装.NETIIS的部分:

       Aspnet_regiis –i

       注意:这个技巧并不仅仅是“对.NET配置IIS”特性;当ASP.NET不能在你的机器上工作时,使用它来“修补”IIS

       如果你只是丢失了ASP.NET使用的客户端脚本文件(JavaScript文件,经常发现在/aspnet_client/system_web/version文件夹),只需运行这个工具如下:

       Aspnet_regiis –c

       最后,这个工具对于使ASP.NETIIS6下工作是有用的。如你所知的,Windows 2003服务器版缺省状态下ASP.NET并不能工作。通过选择IIS>扩展你能使ASP.NET工作,但如果你需要通过脚本让它工作,只需运行工具如下:

       Aspnet_regiis -enabled

预编译你的ASP.NET Web应用

       无论什么时候你使用VS.NET编译你的Web应用,所有它作的就是编译你的代码后置类到程序集中。对首次访问即时编译的Web站点时,你将发现ASP.NET引擎同样要经历它的编译器,这会引起的非常显著的初始延缓。.NET框架2.0安装提供给你几个有用的工具来执行这个ASP.NET编译。

       到虚拟的URLhttp://localhost/MyWebApplication/precompile.axd。如同你在第三章“通过Tarce.axd调试你的ASP.NET Web应用”中你遇到的trace.axd HTTP处理体一样,这个虚拟的URL也被实现使用一个HTTP处理体。处理体遍历你的整个Web应用并预编译所有的页面以避免这个初始延缓。所以在发布你的Web站点后,记住运行这个HTTP处理体。

       你也能使用新的aspnet-compiler.exe工具自动化完整的编译。它定位于.NET框架2.0目录(c:\Windows\Microsoft.NET\Framework\v2.0.*)。

       运行这个工具如下:

       Aspnet_compiler –v /MyWebApplication

       这个命令编译你的整个Web应用(VS.NET使用同样的过程)并预编译Web应用,所以当你首次访问你的Web站点时并不会经历初始延缓。

Web应用设置ASP.NET版本

       缺省状态下,ASP.NET Web应用总是使用给定机器上可用的最新的.NET框架版本(对于Windows应用正好相反,它总是试图使用它被编译时使用的.NET框架版本)。问题是在你安装了.NET框架2.0以后,你的所有的Web应用会使用.NET框架2.0版本,可能这并不是你相要的。

       .NET框架2.0安装会在IIS的虚拟目录的属性对话框上增加一新的Tab页。简单地到IIS,右击你的虚拟目录,从弹出的菜单上选择属性。在ASP.NET Tab页上现在你能设置你的Web应用运行时所需要的版本(见图92)。

 

92      IIS上对你的Web应用设置ASP.NET版本

手工清除程序集缓冲

       当嵌有Windows窗体应用的Web页面运行时,应用首先下载到你的计算机上,缓冲接着从缓冲处运行。在嵌在页面上的应用运行时(像Javaapplets),代码总是从你的当地的计算机上运行(当然,需要所有必需的高安全级的设置)。当原作者决定更新应用时,一个有新的版本号的生成版本会强迫IE下载新的版本。

       有时,你想强迫刷新下载一个新的Windows窗体应用。这典型发生在开发人员的计算机上,缓冲阻碍特定类型的Web应用的日常开发。清除临时的Internet文件夹并没有多大用处。相反,你需要手工清除下载的程序集缓冲,它一般处于C:\Windows\Assembly\Download下。作这个工作需要运行.NET工具叫做gacutil.exe,你能从C:\Windows\Microsfot.NET\Framework\v1.0.3705目录下找到。

       运行这个工具如下:

       Gacutil.exe -cdl

对字符串,标签和内连的.NET代码使用Unicode编码

       .NET框架是完全兼容Unicode编码。.NET中的字符串是Unicode字符串,对于处理Unicode编码的字符串并不需要特殊的工作。但更多的是VS.NET不但能让一个字符串拥有Unicode编码的值,而且它本身也完全支持Unicode

       我开发了几个越南的应用。开发者经常问我用越南字符如何显示一个Windows窗体应用或如何存储越南字符到数据库中。事实上你我并作什么特殊处理,它就能工作。

       VS.NET编辑器中设计我的Windows窗体应用时,我简单地转向语言工具(例如Windows的全局输入方法编辑器或第三方的工具如VPSKeys)接着用Unicode字符设置按钮和标签的值。

       因为VS.NET中的编辑器是Unicode兼容的,我能以Unicode编码输入字符串,通过选择文件>高级保存选项我能以Unicode编码兼容的格式(Unicode,UTF-8,和其它的)保存我的.cs/.vb文件。

       为了使事情更令人注目,我甚至使用Unicode编码于实际的代码。这种方式,代码的注释,区域标签,变量名称,类名称,甚至方法名称都能包含Unicode字符(见图93)。

 

93      在符号名称,字符串,注释等中使用Unicode编码

重新抛出同一个异常

       当一个异常需要记录时,开发者倾向使用类似下面的代码来记录一个异常,但并不吞没异常:

Try

{…}

catch(Exception ex)

{

Log(ex);

Throw ex;

}

       这段代码执行后异常并没有被吞没,因为在结尾处被重新抛出。但是,开发者并没有意识到以这种方式重新抛出异常会引发.NET清除异常的堆栈跟踪。当你探测异常的堆栈跟踪属性时,似乎在catch块中异常是第一次被抛出。

       为了正确地在一个catch块中抛出同样的异常,简单地使用“throw;”如下:

Try

{…}

catch(Exception ex)

{

Log(ex);

Throw;

}

       它会重新抛出同样的异常,并不会清除堆栈跟踪。

posted on 2006-11-05 21:29  漂泊者  阅读(2392)  评论(4编辑  收藏  举报

导航