ASP.NET/页面结构分析
除了与标准 HTML 页面相似之外,您还会注意到 ASP.NET 页面具有一些额外的功能。其中第一个是页面的第一行,它包含一个带有三个属性的“页面指令”。
<%@ Page Language="VB" %>
如果页面是用 C# 编写的,则页面指令将采用这种形式
<%@ Page Language="C#" %>
页面指令用于指定影响整个 ASP.NET 页面的设置。ASP.NET 页面可以用多种不同的语言编写,因此我们必须指定此页面使用哪种语言。debug 属性告诉 IIS Web 服务器(或任何其他能够理解它的 Web 服务器)在页面底部打印调试信息。trace 属性告诉 IIS 打印有关页面执行的更详细的信息,包括跟踪变量。页面指令使用特殊的定界符包含
<%@ %>
接下来你会注意到,这个页面与普通基于 HTML 的页面不同的是,它紧随页面指令之后的脚本块。
<script runat="server"> ' ASP.NET page code goes here Sub Page_Load()
End Sub </script>
虽然脚本块本身在网页中并不罕见,但这个脚本块很特殊,因为它包含 runat="server" 属性。此属性是 ASP.NET 特有的,表示此脚本块将包含服务器端代码。在脚本块中,我们看到了一些 Visual Basic .NET (VB.NET) 代码结构的示例。第一个是注释。Visual Basic 中的注释以撇号开头。撇号之后的所有内容都将被忽略。
VB.NET
' this is a comment in VB.NET
C#
// this is a comment in C#
VB.NET 中没有多行注释定界符。每行注释都必须以撇号开头。
VB.NET
' this is a multiline comment ' in VB.NET
C#
/* this is a multiline comment in C# */
在第一个注释下方,我们看到 Page_Load() 方法。
Sub Page_Load() End Sub
方法(也称为“子例程”、“子程序”或“函数”)是命名的代码块,可以通过调用它们的名称来执行。
- 子例程 - 封装代码,但不返回值给上游调用者。
- 函数 - 封装代码,可以返回值给上游调用者。
Page_Load() 方法是一个特殊的执行方法,每次页面在浏览器中加载时都会执行。由于此方法在每次页面加载时都会执行,因此它是一个定义变量和启动许多进程的有用地方。在 Page_Load() 子例程中,我们可以看到一个 VB.NET If/Then 结构。
If Page.IsPostBack Then End If
在 C# 中,它看起来像这样
if (Page.IsPostback) { }
此条件语句测试页面是否为“回发”页面。我们将在后面更详细地讨论回发机制。目前,请知道,此块中的任何内容在页面第一次加载时都不会执行。但是,如果页面上的提交按钮被按下,它将执行。
最后,脚本块结束。请注意,我们讨论过的所有代码都在页面的开始 HTML 标记之前发生。所有这些代码将在发送任何页面输出到浏览器之前在服务器上执行。
页面主体中唯一不同寻常的是表单标记。表单标记在 HTML 中很常见,但这个表单标记包含我们在脚本标记中看到的相同的 runat="server" 属性。这应该表明您,这个标记在 ASP.NET 中也有特殊的意义。
以下是用 VB.NET 和 C# 编写的功能齐全的 ASP.NET 页面。它演示了一些我们将在下面讨论的概念:变量声明、变量赋值、输出变量以及使用 CSS 格式化输出。以下是 VB.NET 代码。
<%@ Page Language="VB" trace="false" %> <script runat="server"> Sub Page_Load() ' declare variables Dim strCarMake as String Dim strCarModel as String ' assign variables strCarMake = "Mini" strCarModel = "Cooper" ' set label text values lblCarMake.Text = strCarMake lblCarModel.Text = strCarModel If Page.IsPostBack ' postback code goes here End If End Sub </script> <html> <head> <title></title> <style type="text/css"> .box001 { font-family: "trebuchet ms", verdana, sans-serif; } </style> </head> <body> <form runat="server"> <asp:label id="lblCarMake" runat="server" cssclass="box001"/> <asp:label id="lblCarModel" runat="server" cssclass="box001"/> </form> </body> </html>
以及相同的 C# 页面。
<%@ Page Language="C#" trace="false" %> <script runat="server"> void Page_Load(object sender, EventArgs e){ // declare variables string strCarMake; string strCarModel; // assign variables strCarMake = "Mini"; strCarModel = "Cooper"; // set label text values lblCarMake.Text = strCarMake; lblCarModel.Text = strCarModel; if(Page.IsPostBack){ // postback code goes here } } </script> <html> <head> <title></title> <style type="text/css"> .box001 { font-family: "trebuchet ms", verdana, sans-serif; } </style> </head> <body> <form runat="server"> <asp:label id="lblCarMake" runat="server" cssclass="box001"/> <asp:label id="lblCarModel" runat="server" cssclass="box001"/> </form> </body> </html>
将此页面保存在服务器上,命名为 variable_test.aspx,并在浏览器中加载它。您应该看到以下内容显示
Mini Cooper
打印两个词需要这么多代码,但它演示了一些有用的概念。因此,让我们通过分别检查每个部分来仔细看看它。我们从 Page_Load() 子例程(或 C# 行话中的 void 方法)开始。该块中发生了三件重要的事情。首先,我们声明了两个变量。在 VB.NET 中
' declare variables Dim strCarMake as String Dim strCarModel as String
以及在 C# 中
// declare variables string strCarMake; string strCarModel;
在 VB.NET 中,关键字“Dim”是“Dimension”的缩写。使用它表示我们想定义变量的维度,这意味着我们要为变量创建一个名称并定义它的类型。在 C# 中,我们必须在变量名称之前加上它的“类型”(在本例中为“string”),不需要其他内容(不要忘记在行末添加分号)。我们的第一个变量是“strCarMake”。由于我们要在此变量中存储文本,因此我们将它定义为字符串(字面意思是一串字符)。我们对 strCarModel 做同样的事情。在这两种情况下,我们都选择在变量名称前添加一个三字母前缀来表示它的类型。因此,当我们在代码中看到 strCarMake 时,我们就知道 strCarMake 应该包含一个字符串。这是一个方便的做法,但不是必需的(在 C# 中是必需的,当然)。
声明一个变量意味着为它分配内存,并为它关联一个名称,以便我们以后可以轻松地引用它。但是,我们还没有将任何内容放入我们的变量中。在接下来的几行中,我们为它们分配值。在 VB.NET 中
' assign variables strCarMake = "Mini" strCarModel = "Cooper"
以及在 C# 中
// assign variables strCarMake = "Mini"; strCarModel = "Cooper";
等号在这里(与大多数编程语言一样)被称为“赋值运算符”。因此,直到我们说不同,strCarMake 将包含字符串“Mini”,而 strCarModel 将包含字符串“Cooper”。
现在我们的变量已经声明并赋值,但我们需要一种方法将它们显示在我们的页面上(这并不总是必要的,但在我们的示例中是必要的)。将变量内容回显到屏幕上的一个简单方法是将它们与标签关联。以下几行创建了两个标签,并将它们的“.Text”属性设置为等于我们的变量。前缀“lbl”是“label”的缩写,是可选的,但很有用。VB.NET
' set label text values lblCarMake.Text = strCarMake lblCarModel.Text = strCarModel
C#
// set label text values lblCarMake.Text = strCarMake; lblCarModel.Text = strCarModel;
向下看页面的主体,您会看到这些标签放置的位置
<asp:label id="lblCarMake" runat="server" cssclass="box001"/> <asp:label id="lblCarModel" runat="server" cssclass="box001"/>
以上是称为“ASP 控件”的特殊 HTML 标签的示例。ASP 控件有很多类型。这种类型被称为“标签”。可以将标签视为简单的占位符,您可以对其进行编程控制。这里要特别注意的是,每个标签的 ID 属性都使用我们之前定义的相同名称。当 ASP.NET 引擎看到一个标签控件时,它会使用 ID 属性来决定如何处理标签(在本例中,应该在其中放置什么文本)。我们已经告诉它 lblCarMake 应该包含 strCarMake 包含的任何内容。因此,第一个标签变为“Mini”。我们还告诉它 lblCarModel 应该包含 strCarModel 包含的任何内容。因此,第二个标签被替换为字符串“Cooper”。
您会注意到,我们的<asp:label> 还有另外两个属性。一个是 RUNAT,它被设置为“server”。这是一个必需的属性,让 ASP.NET 知道要处理标签。另一个属性是 CSSCLASS。我们可以使用此类将 CSS 类与我们的标签相关联。此页面的 CSS 定义在 HTML 标题内
<style type="text/css"> .box001 { font-family: "trebuchet ms", verdana, sans-serif; } </style>
虽然 CSS 超出了本书的范围,但您可能很容易地看出,名为“box001”的样式有一个名为“font-family”的属性,它告诉任何支持 CSS 的浏览器以“trebuchet ms”(如果系统上可用)显示与“box001”关联的任何内容,或者 verdana(同上),或者任何定义为系统通用无衬线字体的字体(如果前两个都不存在)。
关于我们的示例,还有其他几件事需要注意。首先,看看页面顶部,注意我们的回发块是空的,除了一个注释。VB.NET
If Page.IsPostBack ' postback code goes here End If
C#
if(Page.IsPostBack){ // postback code goes here }
对于此页面,所有操作都在页面加载时完成(在 C# 中,良好的编码习惯要求在括号内包含两个参数 - “object sender, EventArgs e”)。我们甚至没有页面上的提交按钮,因此无法发布任何内容。我们包含条件语句只是为了完整性,以防我们打算以后扩展页面(我们将会这样做)。
在页面的主体中,请注意,我们的<asp:label> 标签嵌套在一些特殊的表单标记内,这些标记具有相同的 RUNAT 属性
<form runat="server"> <asp:label id="lblCarMake" runat="server" cssclass="box001"/> <asp:label id="lblCarModel" runat="server" cssclass="box001"/> </form>
似乎<form> 标记和<asp:label> 标记都包含 RUNAT 属性是多余的。的确是多余的。也要习惯这一点。
如果在浏览器中查看上面的页面,然后选择查看页面的源代码,您会注意到一些服务器端脚本语言的通用内容,以及一些 ASP.NET 的特定内容。为了格式化,我简化了 INPUT 标记的 VALUE 属性。在您看到“[...]”的地方,将是一长串难以理解的字符。
<html> <head> <title></title> <style type="text/css"> .box001 { font-family: "trebuchet ms", verdana, sans-serif; } </style> </head> <body> <form name="_ctl0" method="post" action="simple_variable_test.aspx" id="_ctl0"> <input type="hidden" name="__VIEWSTATE" value="[...]" /> <span id="lblCarMake" class="box001">Mini</span> <span id="lblCarModel" class="box001">Cooper</span> </form> </body> </html>
服务器端语言在安全性方面和对于专有项目的保密性方面提供了一个巨大的优势,因为它可以隐藏大量的代码,使其不会被浏览器看到。当 Web 浏览器向 Web 服务器请求页面时,服务器会检查该页面。如果服务器识别出该页面需要由服务器端脚本引擎进行处理,它会将页面传递给该引擎进行处理。处理引擎(这里指的是 ASP.NET)完成工作后,将页面返回给 Web 服务器,Web 服务器再将最终产品传递给浏览器。你上面看到的代码是浏览器接收到的所有代码。请注意,所有 ASP.NET 特定的代码都消失了,尽管有一些迹象表明这是一个 ASP.NET 页面。
Web 服务器通常根据文件扩展名来确定哪些页面需要使用哪种处理引擎。ASP.NET 页面通常以 .aspx 结尾(尽管可以通过 Web 服务器的自定义配置来定义其他任何扩展名)。PHP 页面以 .php 结尾。HTML 页面通常以 .html 或 .htm 结尾。
请注意,在页面被处理后发生了一些变化。<asp:label> 标签变成了普通的 <span> 标签。它们的 CSSCLASS 属性变成了简单的 CLASS 属性。它们的 ID 属性保持不变。而神秘的 RUNAT 属性则完全消失了。我们的 <form> 标签还在,但它的 RUNAT 属性不见了,其他几个表单标签常见的属性也出现了。
有趣的是,除了 <span> 标签之外,还添加了一个新的 <input> 标签到表单中。请注意,它的属性是“hidden”。隐藏的输入标签用于在 Web 编程中将变量的值从一个页面传递到另一个页面。如果这个表单包含一个提交按钮,那么我们的标签的值将通过这个 <input> 标签的 NAME 和 VALUE 属性传递到 <form> 标签的 ACTION 属性中定义的页面。在许多服务器端编程语言中,你必须自己编写这个功能。ASP.NET 帮你做了这个,尽管方式有点隐蔽。