第3章 ASP.NET语法
如果读者熟悉ASP,就会发现ASP.NET的很多语法是非常类似于ASP的。但ASP.NET引入了许多新特性,例如编译型的编程语言、服务器端的事件处理、Web控件等,因此相应的ASP.NET也引入了一些新的语法。
本章主要内容如下:
● 两种编写服务器端代码的方法
● 引入外部代码
● 在服务器端、客户端及代码内部使用注释
● HTML服务器控件
● Web服务器控件
● 服务器端包含指令
● 服务器端对象标志语法
● 数据绑定语法
3.1 服务器端代码
在介绍单文件版本的Web窗体窗体时,提到过两种编写服务器端代码的方法:<Script runat=server>…</Script>和<%… %>。第一种方法撰写服务器端代码构成一个代码声明块。第二种方法撰写的服务器端代码构成一个呈现代码块。
代码声明块定义将编译为生成的Page派生类的成员变量和方法。而呈现代码块则不同,它们在编译后不会成为派生类的任何成员,而是成为Web窗体派生类的呈现逻辑的一部分。
提示
Web窗体在其生命周期中有几个典型的阶段。呈现阶段是Web窗体生命周期的最后一个阶段,在这一阶段,Web窗体被ASP.NET框架翻译成对应的HTML代码,翻译时,要执行呈现代码块。
请读者一定要注意,所有的函数和全局页变量都必须在 <Script runat=server> 标志中声明,在<% %> 块内声明的函数将生成语法编译错误。
呈现代码允许使用<%= ...%>直接把表达式的结果输出,这跟ASP语法类似。例如,实现输出“Hello World”这种形式的代码为:
[Visual Basic] <%="Hello World" %> [C#] <%="Hello World" %>
上面的代码等价于下面的呈现代码:
[Visual Basic] <% Response.Write("Hello World") %> [C#] <% Response.Write("Hello World"); %>
注意
上述C#中代码后的“;”不可少,单如果采取<%=…%>形式,则“;”不需要,如果写成:
[C#] <%="Hello World" ;%> 那么将等价于: [C#] <% Response.Write("Hello World";); %> 这时将发生编译错误。
下面的示例演示如何编写服务器端代码:
[Visual Basic] <Script language="vb"runat=server> function add(num1 as integer,num2 as integer)as integer return num1 + num2 end function function subtract(num1 as integer,num2 as integer)as integer return num1 - num2 end function </Script> <html> <title>演示ASP.NET语法</title> <body> 1+2=<%=add(1,2)%> <% '... dim number as integer=subtract(2,1) Response.Write("<p>2-1=" + number.ToString()) '... %> </body> </html> [C#] <Script language="C#" runat=server> int add(int num1, int num2) { return num1 + num2; } int subtract(int num1, int num2) { return num1 - num2; } </Script> <html> <title>演示ASP.NET语法</title> <body> 1+2=<%=add(1,2)%> <% //... int number = subtract(2, 1); Response.Write("<p>2-1="+number.ToString()); //... %> </body> </html>
请读者一定要把服务器端代码和客户端代码区分开来。客户端代码由客户端的浏览器解释执行,因而撰写客户端代码的脚本语言可以是JScript或VBScript,但不能是.NET框架支持的编程语言,如C#、Visual Basic等。事实上,客户端可以对.NET一无所知。
客户端的代码的语法不是ASP.NET所规定,它们由HTML 3.2或更高的标准规定。为了编写客户端代码,请编写一个<Script></Script>块,但不设定runat=server属性,例如:
<html> <head> <title>WebForm1</title> </head> <body bgcolor="#3366cc"> <form id=form1> <input id=name type=text> <input id=ok value=OK type=button onclick="OnOkClick();"> <div id=msg > </div> </form> </body> <Script language=jScript> function OnOkClick() { alert(form1.name.value); } </Script> </HTML>
在浏览器中打开该网页,往文本框中输入一些文本,然后单击【OK】按钮,将弹出一个对话框显示文本框的数值,如图3-1所示。
图3-1 客户端代码执行效果
读者要注意,通过HTML对象模型访问HTML页中的任何对象(实际上是一个HTML标志)的方法。一个HTML中的所有HTML标志被分拆成一棵树状结构。例如,上面的代码具有如图3-2所示的树状结构。
图3-2 HTML代码的树状结构
图3-2中没有用“<>”围起来的就是代码树中的一个节点,这些节点的顶层对象是document对象,通过document.form1可以访问表单对象,通过document.form1.name可以访问文本输入框。所有对象名都是由其ID属性规定的,每个对象具有若干可以通过编程访问的属性。例如,文本输入框有value属性,利用该属性可以读取或设置文本输入框中的文本。作为顶级对象的document对象可以省略不写,这样访问name文本输入框的代码可以简化为form1.name。
提示
alert方法实际是另一个Window对象的方法,Window表示浏览器的当前窗口。如果HTML页面包含多个帧(Frame),那么Window对象比较有用,这时每个帧都可以包含一个document对象,可以从Window对象出发获得特定的帧,然后进一步获得该帧包含的document对象,例如:
window.frames(0).document
上面的代码获得第一个帧的document对象。
上面的讨论也提醒读者,编写客户端代码的所使用的模型是所谓的HTML对象树模型,读者需要了解诸如Window、document等对象。
在客户端撰写脚本而不是在服务器端编码,能够减少服务器负担,降低网络流量,但请读者注意,客户端的脚本不具任何安全性。通过查看HTML文件的源代码,就可以把其中的客户端脚本看得一清二楚。
3.2 注释
准确的注释对帮助别人理解代码至关重要,为代码添加必要的注释是一个值得提倡的编程做法。
在ASP.NET编程实践中,读者要碰到两种注释:一种是HTML内的注释;另一种是代码内的注释。
HTML内的注释包括两小类:客户端和服务器端。客户端的HTML注释看起来如下所示:
<!-- HTML客户端注释 -->
注释和注释标志也可以位于同一行:
<!--HTML客户端注释 -->
注意
“<!--”和“--->”要紧挨在一起,之间不能有空格,但注释内容和“--”之间则允许有空格。
服务器端的HTML注释看起来如下所示:
<%-- 服务器端的注释 --%>
或:
<%-- 服务器端的注释 --%>
注意
“<%--”和“--%>”要紧挨在一起,之间不能有空格,但注释内容和“--”之间则允许有空格。
代码内的注释,则跟所使用的语言有关:
如果为JScript或C#,则一行中符号“//”后的内容为注释。另外,符号“/*”和符号“*/”之间的内容也是注释。
如果为VBScript或Visual Basic,则一行中符号“'”后的内容为注释。
3.3 引入外部代码
在ASP编程时代,有经验的开发人员会把相关的功能在一个文件中实现,然后通过include指令引入到页面。ASP.NET保留了这种引入外部代码的能力,其实现的原理是设定Script脚本的src属性。
提示
当对Script脚本使用了src属性后,将忽略声明块中的任何其他代码。
下面的示例说明了如何为EnterBtn_Click事件定义事件处理逻辑。
[Visual Basic] <% @page language="vb" %> <html> <Script runat="server"src="file.vb"/> <body> <form runat="server"> 输入你的名字: <asp:textbox id="Name" runat=server/> <asp:button text="显示" Onclick="EnterBtn_Click" runat="server"/> <p> <asp:label id="Message" runat=server/> </form> </body> </html> 其中file.vb的内容如下: sub EnterBtn_Click(Src as Object, E as EventArgs) Message.Text="你好,"+Name.Text+", 欢迎进入ASP.NET!" end sub [C#] <% @page language="cs" %> <html> <Script runat="server"src="file.cs"/> <body> <form runat="server"> 输入你的名字: <asp:textbox id="Name" runat=server/> <asp:button text="显示" Onclick="EnterBtn_Click" runat="server"/> <p> <asp:label id="Message" runat=server/> </form> </body> </html> 其中file.cs的内容如下: void EnterBtn_Click(Object Src, EventArgs E) { Message.Text="你好,"+Name.Text+", 欢迎进入ASP.NET!"; }
执行结果如图3-3所示。
图3-3 执行结果
提示
在file.vb或file.cs中,请不要把代码放在<Script runat=server>和<server>之间,否则会出现编译错误。
3.4 服务器端包括指令
该指令可以把指定文件的内容插入到ASP.NET页的任意位置,其基本用法如下:
<!-- #include file= filename -->
或:
<!-- #include virtual = filename -->
第一种格式指定插入的文件的所在的物理路径。此路径可以是相对的。
提示
被包含的文件可以在同一个目录或子目录中,但不能在具有 #include指令的页的上级目录中。
第二种格式用虚拟路径表示插入的文件所在的位置。此路径可以是相对的。
提示
尽可能的用第二种格式,因为文件的物理路径有可能会更改。
关于该指令需要注意以下几点:
● 被包含文件的文件名值必须括在引号 ("") 中。
● 在执行任何动态代码之前处理被包含的文件。
● #include标志必须括在HTML/XML注释分隔符中以避免被解释为文本。
下面的示例说明了如何使用服务器端包括语法来调用将在ASP.NET页上创建页眉和脚注文件。两个文件都使用相对路径。
<html> <body> <!-- #Include virtual=".\include\header.inc" --> Here is the main body of the .aspx file. <!-- #Include virtual=".\include\footer.inc" --> </body> </html>
3.5 服务器控件
服务器控件是可以在服务端访问的对象,ASP.NET框架把服务器组件成现为客户端的HTML代码。服务器控件的runat属性都设置为server,并且可以通过其ID属性而被引用。
服务器控件细分为两类,一类为Web服务器控件,另一类为HTML服务器控件。两类的区别是后者的控件直接对应到某个HTML元素,其属性也对应到HTML元素的属性;而前者对应到HTML元素的过程不那么直接,这类控件的属性大多也跟HTML元素属性毫不相关,ASP.NET框架根据目标浏览器及控件本身的属性,产生一段恰当的HTML代码返回给客户(这个过程叫呈现)。
这里我们讨论两类控件的一般用法,本书后面将有专门的章节深入讨论这些控件的具体用途和用法。
3.5.1 HTML服务器控件
将一个HTML元素,设置runat的属性为server后,该元素就转化为服务器控件。例如,下面的代码定义了一个服务器端的表单控件:
<form id="WebForm1" method="post" runat="server"> </form>
提示
每一个Web窗体必须包含一个服务器端的表单控件。
下面的代码则定义了一个HTML服务端的标签控件,其实质是一个runat=server的<DIV></DIV>标志。
<DIV runat=server>标签</DIV>
提示
在Visual Studio.NET Web窗体设计器的设计视图下,选中一个HTML控件,单击右键,单击【作为服务器端控件运行】按钮,会自动将其runat属性设置为true。
在服务器端,可以通过HTML元素的ID属性引用该控件。例如:
[Visual Basic] <Script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) Message.InnerHtml = "欢迎使用ASP.NET" End Sub </Script> ... <span id="Message" style="font-size:24" runat="server"/> [C#] <Script language="C#" runat="server"> void Page_Load(Object sender, EventArgs e) { Message.InnerHtml = "欢迎使用ASP.NET"; } </Script> ... <span id="Message" style="font-size:24" runat="server"/>
3.5.2 Web服务器控件
在Web页引入Web服务器控件时,需要指定命名空间ASP,并将其runat属性设置为server,例如<asp:label runat="server">引入一个标签服务器控件,该控件与System.Web.UI.WebControls命名空间中的Label类相对应,在动态编译.aspx文件的时候,会自动引入System.Web.UI.WebControls命名空间。
通过添加ID为“Message”的标志,在运行时创建Label的实例:
<asp:label id="Message" font-size=24 runat="server"/>
然后可用同一名称访问此控件。下面的代码行设置此控件的Text属性:
[Visual Basic] Message.Text = "Welcome to ASP.NET" [C#] Message.Text = "Welcome to ASP.NET";
3.6 服务器端对象标志语法
对象标志使页开发人员能够用基于标志的声明语法声明和创建变量的实例,该实例既可以是.NET对象,又可以是COM对象。若要创建.NET对象,采用下面格式的语法:
<object id="id" runat=server latebinding=true|false class=".NET Framework Class Name">
其中id为当引用后面的代码中的对象时使用的惟一名称,Class指定要创建的 .NET框架类。
提示
当ASP.NET页分析器在.aspx文件中遇到服务器端对象标志时,它使用该标志的ID属性作为属性名在该页上生成只读属性,当用户请求一个属性时,将获得一个Class指定的对象实例。
下面的示例说明了如何在Web窗体页中创建ArrayList.NET框架类的实例。
[Visual Basic] <html> <object id="items" class="System.Collections.ArrayList" runat=server/> <Script language="VB" runat=server> Sub Page_Load(Sender As Object, E As EventArgs) items.Add("One") items.Add("Two") items.Add("Three") MyList.DataSource = items MyList.DataBind() End Sub </Script> <body> <asp:datalist id="MyList" runat=server> <ItemTemplate> 数值: <%#Container.DataItem %> </ItemTemplate> </asp:datalist> </body> </html> [C#] <html> <object id="items" class="System.Collections.ArrayList" runat=server/> <Script language="C#" runat=server> void Page_Load(Object sender, EventArgs e) { items.Add("One"); items.Add("Two"); items.Add("Three"); MyList.DataSource = items; MyList.DataBind(); } </Script> <body> <asp:datalist id="MyList" runat=server> <ItemTemplate> 数值:<%# Container.DataItem %> </ItemTemplate> </asp:datalist> </body> </html>
上述代码等价于:
[Visual Basic] <html> <Script language="VB" runat=server> private items as new System.Collections.ArrayList …. </Script> … </html> [C#] <html> <Script language="C#" runat=server> private System.Collections.ArrayList items = new System.Collections.ArrayList(); …. </Script> … </html>
提示
上述代码编译后都生成一个位于ASP命名空间从System.Web.UI.Page派生的类,而Items是该类的一个成员。
如果要创建COM对象实例,则相应的语法格式是:
<object id="id" runat=server latebinding=true|false progid="COM ProgID"/> 或: <object id="id" runat=server latebinding=true|false classid="COM ClassID"/>
其中,ProgID是COM组件的编程标识符,ClassID是COM组件的类标识符。
下面是利用这种格式的指令在页上引入ADO对象模型中的Connection对象:
[Visual Basic] <%@ page language="vb" %> <html> <object id="myConn" runat=server latebinding=false progid="ADODB.CONNECTION"/> <Script runat=server> sub outPutHtml() '显示版本 Response.Write(myConn.Version) '其他操作 end sub </Script> <body> <%outPutHtml()%> </body> </html> [C#] <%@ page language="C#" %> <html> <object id="myConn" runat=server latebinding=false progid="ADODB.CONNECTION"/> <Script runat=server> void outPutHtml() { //显示版本 Response.Write(myConn.Version); //其他操作 } </Script> <body> <%outPutHtml()%> </body> </html>
注意
不能在同一个服务器端对象标志中同时设定classid、progid和class属性,而只能使用其中的某一个。
开发人员还可以利用ASP.NET向开发人员公开熟悉的Server.CreateObject(ProgId) API来创建COM的晚期绑定引用。这时请把页面的@Page指令的ASPCompat属性设为true:
<%@Page ASPCompat="true" %>
下面利用这种方法创建一个ADODB.Connection对象,然后调用Open方法打开一个名为pubs的ODBC数据源(该数据源链接到SQLServer的pubs数据库),接下来调用链接对象的Execute方法获得一个RecordSet对象,紧接着遍历RecordSet对象,最后关闭记录集和链接。
<%@ page language="vb" aspcompat=true %> <html> <Script runat=server> sub outPutHtml() dim conn =Server.CreateObject("adodb.connection") conn.Open("pubs") dim rs =conn.Execute("select au_lname,au_fname from authors") while not rs.EOF Response.Write("Last Name="&rs("au_lname").Value) Response.Write(" First Name="&rs("au_fname").Value) Response.Write("<br>") rs.MoveNext() end while rs.Close() conn.Close() end sub </Script> <body> <%outPutHtml()%> </body> </html>
执行结果如图3-4所示。
图3-4 执行结果
提示
在.NET框架下使用COM对象的一般方法是利用.NET的互操作服务把COM对象包装成.NET组件,然后通过包装的.NET组件间接地访问COM对象。
3.7 数据绑定语法
ASP.NET支持分层数据绑定模型,该模型支持服务器控件属性和父数据源之间的关联绑定。任何服务器控件属性都可以把数据绑定到任何公共字段或属性,这些公共字段或属性位于包含页或服务器控件的直接命名容器上。
所有数据绑定表达式都必须包含在<%#和%> 字符中,与它们的位置无关。位于<%# %> 代码块中的代码只有在其父控件容器的DataBind方法被调用时才被执行。下面的示例说明如何在<asp:datalist runat=server>控件内使用数据绑定语法。
<asp:datalist id="MyList" runat=server> <ItemTemplate> 数值:<%# Container.DataItem %> </ItemTemplate> </asp:datalist>
上面的代码在数据列表内指定了一项模板(ItemTemplate)。用数据绑定表达式指定项模板的内容,对数据源中的每一项数据,都重复套用一次模板,其中的Container.DataItem引用数据列表MyList所使用的数据源的当前数据项。
本例中,以编程方式设置MyList控件的数据源,然后调用DataBind()。
[Visual Basic] Sub Page_Load(sender As Object, e As EventArgs) Dim items As New ArrayList() items.Add("One") items.Add("Two") items.Add("Three") MyList.DataSource = items MyList.DataBind() End Sub [C#] void Page_Load(Object sender, EventArgs e) { ArrayList items = new ArrayList(); items.Add("One"); items.Add("Two"); items.Add("Three"); MyList.DataSource = items; MyList.DataBind(); }
关于数据绑定,本书后面还要做进一步的讨论。
3.8 小结
本章介绍的知识将被广泛应用。读者要掌握编写服务器端代码的<Script runat=server>和<%%>方法,使用其他文件中的代码能在代码级别实现重用。本章介绍的服务器端包含指令和引入外部指令的语法都能做到这一点,在服务器端使用控件也是ASP.NET的新特性。本章介绍了两类服务器组件的引入、属性设定的规则,对绑定的支持是ASP.NET的新内容,注意不要把绑定语法<%#%>跟服务端代码声明搞混了。