第十部分 附录
附录A 从ASP迁移到ASP.NET
本附录主要内容:
l ASP.NET页面以.ASPx扩展名结束
l OptionExplicit是默认打开的
l 不再有变体
l 在向子例程和方法传递参数时使用圆括号
l 必须在<Script>标记中声明函数和子例程
l 参数是通过值传递的
l 表单应该被提交回相同的页面
l 每个页面只有一个服务器端表单
l 在操作对象时不使用 Set和Let
l 不支持场所线程的组件
l 没有无索引的默认属性
l ASP.NET页面只能包含一种语言
l Request、Request.Form和Request.QueryString的差异
本附录提供从以前的 ActiveServerPages版本移植到ASP.NET的相关信息。如果你早就是一位ActiveServerPages开发者,你可能问的第一个问题会是” ASP.NET与以前的 ActiveServerPages版本兼容吗?”换句话说,你想知道是否能够轻松地将现有的 ActiveServerPages网站升级到ASP.NET,而不必重写任何代码。这个问题的答案比较复杂。在一般情况下, ASP.NET完全向后兼容以前的 ActiveServerPages版本兼容吗?”换句话说,你想知道是否能够轻松地将现有的 ActiveServerPages网站升级到ASP.NET,而不必重写任何代码。
这个问题的答案比较复杂。在一般情况下, ASP.NET完全向后兼容以前的 ActiveServerPages版本。只要用扩展名.ASP命名页面,那么就会使用 ASP.dll执行它们, ASP.dll是用于执行以前的 ActiveServerPages版本的引擎。但是,如果执行扩展名为.ASP的页面,你就享受不到ASP.NET的好处。例如,得不到动态页面编译和页面缓存的速度优势,也不能访问数千个.NET类中封装的功能。
真正的答案是,必须对现有的ASP页面做一些处理,才能让它们在新的ASP.NET框架中工作。你必须将VBScript页面移植为VisualBasic.NET,甚至必须重新构造网站才能充分利用 ASP.NET框架。在下面几节中,我将描述传统 ActiveServerPages与ASP.NET之间的几个重要改变。
A.1 ASP.NET页面以.aspx扩展名结束
传统ASP页面以.ASP扩展名结束,而ASP.NET页面以.ASPx扩展名结束。如果有一些链接指向你的网站,那么以上情况就非常麻烦。例如,你的网站可能有数百个采用.ASP扩展名的页面,搜索引擎(比如 AltaVista或Google)已经对它们进行了索引。你可能不想修改这些文件名的扩展名,因为你不希望失去在搜索引擎中的级别。
实际上,你可以为 ASP.NET页面使用你喜欢的任何扩展名。要想修改 ASP.NET页面使用的扩展名,请执行以下步骤:
1 ) 选择Start|Programs|AdministrativeTools|InternetServicesManager,启动InterNETServicesManager。
2 ) 右击你的网站的名称并且选择 Properties,打开网站的属性单。
3 ) 选择HomeDirectory选项卡。
4 ) 在ApplicationSettings部分中点击Configuration按钮。
5 ) 在ApplicationConfiguration对话框中选择AppMappings选项卡。
6 ) 在默认情况下, ASPNET_isapi.dll文件被映射到.ASPx扩展名。如果点击 Edit,你可以将ASPNET_isapi.dll文件映射到你选择的任何扩展名。例如,如果映射到.ASP文件,那么以.ASP扩展名结束的所有页面将被当作 ASP.NET页面。(在这样做之前,需要删除对.ASP文件的现有映射。)
在完成以上步骤之后,具有.ASP扩展名的页面将由ASP.NET引擎处理。但是,你还必须完成几个步骤,它们才能发挥 ASP.NET页面的作用:
1 ) 用 Notepad打开Web服务器的machine.config文件。machine.config文件位于WINNT\Microsoft.NET\Framework\[version]\CONFIG目录下。
2 ) 找到<httpHandlers>部分。这个部分列出了具有.ASPx、.asmx和.ASP扩展名的文件的处理器。
3 ) 将.ASP文件的处理器改为System.Web.UIPageHandlerFactory:
<add
verb= “*“
path= “*.ASP“
type=“System.Web.UI.PageHandlerFactory, System.Web, Version=1.0.2411.0,ˉCulture= neutral, PublicKeyToken=b03f5f7f11d50a3a” />
最后这三步将.ASP文件与正确的处理器关联起来。如果忽略了这些步骤,那么在打开.ASP文件时会收到错误消息。
A.2 OptionExplicit是默认打开的
在以前的 ActiveServerPages版本中,OptionExplicit是默认关闭的。但是在 ASP.NET中,OptionExplicit是默认打开的。
当OptionExplicit打开时,必须声明变量,才能使用它。例如,尽管以下脚本在传统 ASP中工作正常,但是在ASP.NET中会产生错误:
<%strMessage= “Hello, howareyou?”
Response.Write( strMessage)
%>
如果执行包含此脚本的 ASP.NET页面,会收到错误消息 Thename ‘strMessage’isnotdeclared。
可以用两种办法避免这个错误。如果你希望保持优秀的编程习惯并且从 ASP.NET页面得到最佳性能,那么应该在使用所有变量之前声明它们,比如:
<%DimstrMessageAsStringstr
Message= “Hello, howareyou?”
Response.Write( strMessage)
%>
如果你不想声明所有的变量,也可以在页面级或者服务器级关闭 OptionExplicit。
在页面级关闭OptionExplicit的办法是在页面顶部添加以下的页面指令:
<%@ Explicit=“False”%>
可以在 machine.config文件中为 Web服务器上的所有页面关闭 OptionExplicit(machine.Config文件位于WINNT\Microsoft.NET\Framework\[version]\CONFIG目录下)。在<compilation>部分中,将explicit属性设置为False值。
A.3 不再有变体
VBScript不是强类型的语言。在 VBScript中,不能声明变量的类型,这导致所有变量都作为变体(variant)创建。.NET框架不支持变体。变体在.NET框架中的对应物是Object类型。
请考虑以下脚本。在这个脚本中,声明了一个变量,一个值被赋值给它,然后显示这个变量:
<%
DimstrMessagestr
Message= “Hello!”
Response.Write( strMessage)
%>
因为没有显式地声明 strMessage变量的类型,所以它被当作 Object。在将字符串” Hello!”赋值给这个变量时,它被自动转换为 String数据类型。
将变量自动地转换为合适的类型是很方便的,但是这会对性能产生消极影响。出于性能方面的考虑,应该显式地声明 strMessage的变量类型:
<%DimstrMessageAsStringstr
Message= “Hello!”
Response.Write( strMessage)
%>
将变量自动地转换为正确类型的过程被称为延期绑定( latebinding)。可以使用OptionStrict语句在代码中避免延期绑定。启用 OptionStrict的办法是在ASP.NET页面的顶部添加以下的页面指令:
<%@ Strict=“True”%>
当你启用OptionStrict时,也自动启用OptionExplicit。
也可以在machine.config文件中为每个 ASP.NET页面启用OptionStrict。办法是在<compilation>部分中添加strict=“True”属性。
A.4 在向子例程和方法传递参数时使用圆括号
与传统ASP不同,在ASP.NET中,在向子例程或方法调用传递参数时必须使用圆括号。例如,以下脚本在传统ASP中工作正常:
<%
Response.Write“HelloWorld!”
%>
但是,这个脚本在ASP.NET中会产生一个错误。需要在 Write方法中使用圆括号:
<%
Response.Write(”HelloWorld!”)
%>
在向子例程传递参数时也需要使用圆括号。如果一个子例程不需要任何参数,那么圆括号是可选的。
A.5 必须在<Script>标记中声明函数和子例程
在传统ASP中,可以在代码表达块中声明函数和子例程(除了 Global.asa文件的情况)。例如,以下脚本在传统ASP中工作正常:
<%
FunctionAddNums( intVal1, intVal2 )
AddNums= intVal1 + intVal2
EndFunction
Response.Write( AddNums( 12, 34 ) )
%>
但是,如果试图在 ASP.NET页面中执行这个脚本,就会收到一个错误。你必须在 <Script>代码声明块中声明函数和子例程:
<Scriptrunat=“Server”>
FunctionAddNums( intVal1, intVal2 )
AddNums= intVal1 + intVal2
EndFunction
</Script>
<%
Response.Write( AddNums( 12, 34 ) )
%>
这个新要求的影响是不能在子例程或函数中直接表达内容。例如,以下脚本在传统 ASP中工作正常:
<%
SubShowError
%>
<fontcolor=“red”>Error!</font>
<%
EndSub
ShowError
%>
但是,因为在 ASP.NET中不能在代码表达块中声明函数或子例程,所以需要像下面这样重写代码:
<Scriptrunat=“Server”>
SubShowError
Response.Write(“<fontcolor=““red”“>Error!</font>“ )
EndSub
</Script>
<%
ShowError
%>
A.6 参数是通过值传递的
在VBScript和以前的VisualBasic版本中,参数在默认情况下是通过引用传递给子例程和函数的。
但是在VisualBasic.NET中,参数是通过值传递的。当参数通过值传递给函数时,在函数内对参数的修改不影响参数在此函数外的值。然而,当参数通过引用传递时,对参数的修改在函数外被保留。
仍然可以使用 ByVal和ByRef关键字指定参数是通过值传递,还是通过引用传递。例如,以下页面演示如何显式地指定通过值和通过引用将参数传递给子例程:
<Scriptrunat="Server">
SubAddByVal( ByValintParam)
intParam+= 1
EndSub
SubAddByRef( ByRefintParam)
intParam+=1
EndSub
</ Script>
<%
DimintNumAsInteger= 3
' intNumstillequals3 afterAddByVal
AddByVal( intNum)
' intNumnowequals4 afterAddByRef
AddByRef( intNum)
%>
A.7 表单应该被提交回相同的页面
要想充分利用ASP.NET框架,就不应该创建提交到另一个页面的 HTML表单。如果表单被提交到另一个页面,当前页面维护的视图状态就会丢失。
在传统ASP中,表单将数据提交到另一个页面是非常常见的,如图 A-1所示。
在ASP.NET框架中,操作表单的首选方式是将表单提交回相同的页面。将表单提交回它本身被称为postback。图A- 2演示了postback的执行过程。
图A-1 提交到新页面 图A-2 执行postback
当你将表单提交回它本身时,可以利用视图状态(在各次提交之间自动保留控件的属性值)。在执行postback之后,可以使用Response.Redirect方法将用户转移到新页面。
A.8 每个页面只有一个服务器端表单
ASP.NET框架的一个重要限制是在一个页面中只能有一个服务器端表单。例如,许多网站用同一个页面进行新用户的注册和现有用户的登录。在 ASP.NET框架中,建立这种页面很困难。
ASP.NET框架不允许一个页面包含两个表单,否则就不能利用 ASP.NET功能,比如表单检验和视图状态。你必须将单个页面分割为两个页面。
这个限制不适用于一般的 HTML表单;它只应用于服务器端表单。一个页面中可以包含任意数量的标准客户端表单。
A.9 在操作对象时不使用Set和Let
在以前的ASP版本中,在将对象赋值给变量时必须使用 Set。例如,在创建Connection对象的实例时,使用以下语句:
<%
SetconPubs= Server.CreateObject(" ADODB.Connection")
%>
在使用VisualBasic.NET创建 A S P. N ET页面时,不再使用Set语句,而是使用简单的赋值语句:
<%
conPubs=Server.CreateObject(" ADODB.Connection")
%>
而且,也不再使用Let语句。
A.10 不支持场所线程的组件
在默认情况下,ASP.NET页面不支持使用单线程场所( STA)模型的组件。而且,在默认情况下不支持传统ASP的内在接口,比如OnStartPage和OnEndPage。
如果你希望使用场所线程模型的组件,比如ADOConnection对象或Scripting.Dictionary对象,那么需要在页面顶部添加以下页面指令:
<%@ PageASPCompat="true"%>
例如,以下页面使用传统的 ADO显示Pubs数据库中的Titles表的所有记录。如果不禁用 ASP兼容性,页面会失败。
<%@ PageASPCompat="true" %>
<%
DimconPubs
DimrsTitles
conPubs= Server.CreateObject( "ADODB.Connection" )
conPubs.Open( "Provider=sqloledb;UID=sa;PWD=secret;database=pubs" )
rsTitles= ConPubs.Execute( "Select* fromTitles" )
WhileNotrsTitles.eof
Response.Write( rsTitles( "Title" ).Value)
rsTitles.MoveNext
EndWhile
%>
A.11 没有无索引的默认属性
VisualBasic不再支持无索引的默认属性。例如,在传统 ASP中,不需要显式地调用RecordSet对象的Value属性。以下代码就能显示 RecordSet字段的值:
Response.Write(RS(" Title"))
但是,在ASP.NET中,必须显式地引用属性。所以,需要将这个语句重写为:
Response.Write(RS(" Title").Value)
A.12 ASP.NET页面只能包含一种语言
在传统 ASP中,可以使用 <Script>标记在同一个页面中添加用不同语言编写的脚本。例如,可以创建一个VBScript脚本,让它调用相同页面中的 JScript脚本中的函数,只需将这两个脚本包含在不同的<Script>块中即可。
ASP.NET不支持在同一个页面中使用多种语言。如果你希望混用多种语言,就需要创建单独的组件。例如,可以用 C#创建一个组件,并且在用 VisualBasic.NET编写的ASP.NET页面中访问这个组件的方法和属性。
A.13 Request、Request.Form和Request.QueryString的差异
在传统ASP中,Request、Request.Form和Request.QueryString方法都返回一个字符串数组。在ASP.NET中,这三个方法都返回单个字符串。
传统ASP返回字符串数组是因为 Form或QueryString集合中的多个条目可能具有相同的名称。例如,以下URL将两个同名的条目添加进 QueryString集合:
http:/ / www.Superexpert.com/ Default.aspx? favColor= blue& favColor= green
在传统ASP中,如果希望显示查询字符串变量 favColor的两个值,就需要遍历 QueryString方法返回的字符串数组:
<%
DimfavColor
ForeachfavColorinRequest.QueryString( "favColor" )
Response.Write( favColor)
Next
%>
在ASP.NET中,QueryString()方法总是返回单个字符串。在这个例子中,这个字符串是blue,green。如果你需要返回一个集合而不是单个字符串,就需要使用 GetValues():
<%DimfavColor
ForeachfavColorinRequest.QueryString.GetValues( "favColor" )
Response.Write( favColor)
Next
%>
这一情况也出现在 Request.Form上。如果一个表单包含一个允许多选的列表框,那么 Form集合可能包含多个同名的条目。在传统 ASP中,Request.Form()返回一个字符串数组。而在ASP.NET中,Request.Form()总是返回单个字符串。
注意 由于某些奇怪的原因,在传统ASP中,Request.QueryString和Request.Form返回的字符串数组的下限是1。在ASP.NET中,GetValues方法返回的数组的下限是0。