计算机协同学习技术及应用
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第1章 ASP.NET应用开发概览

ASP.NET是下一代的活动服务页面框架。ASP.NET是.NET框架中的固有部分,利用ASP.NET提供的服务,可以开发出新一代的Web应用。

本章将介绍下面内容:

● HTML、ASP应用和ASP.NET应用的比较

● ASP.NET应用开发前的准备工作

● 用Visual Studio.NET开发第一个ASP.NET应用

1.1 HTML、ASP和ASP.NET

在开始ASP.NET介绍之前,我们先简单追述一下Web应用开发的历史。最初的Web应用是基于静态的HTML文本。利用一些预定义的标志,诸如FrontPage等工具就可以产生这样的文本。HTML较好地解决了信息的显示问题,但这些信息和控制显示格式的标志在服务器端是编码存储的,这时应用程序的执行模式为:客户请求某一个静态HTML文本,服务器返回该文本。下面是一个典型的HTML文本的示例:

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <meta http-equiv="Content-Language" content="zh-cn">
    <title>主页</title>
    <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
    <meta name="ProgId" content="FrontPage.Editor.Document">
    <meta name="Microsoft Theme" content="strtedge 011, default">
    <meta name="Microsoft Border" content="tl, default">
    </head>
    <body>
        <p><font size="4">欢迎光顾我的站点!</font></p>
        <p>主页是让到访者了解本站点主旨的最佳场所。主页向到访者展示了您站点的风格。
</p>
        <p>  </p>
        <p>此网页最近更新于<!--webbot bot="Timestamp" s-type="REGENERATED" s-format=
"%y年%m月%d日" -->。</p>
        <p        align="right"><a        href="http://www.microsoft.com/frontpage/"><img
src="images/frontpag.gif" border="0" width="88" height="44"></a></p>
    </body>
    </html>
上述HTML文本是用FrontPage工具创建的。文本的结构大致如下:
    <html>
    <head>
      <title>主页</title>
    </head>
    <body>
    </body>
    </html>

标志<html></html>之间的是HTML文件的内容。<html>标志指示上述文件为一个HTML文档,<title></title>标志指示文本的标题,<bod></body>之间的是HTML文件的正文。

提示

IE浏览器能够解释结构不完整的HTML文件,所以上述文件中去掉第一行的<html>和最后一行的</html>,也能在浏览器中正确地显示。但建议读者在设计HTML文件时,保证其结构的完整性,因为这样可以增强代码的可读性。

观察上述HTML文件,会发现每个标志都有若干属性,例如,<font size="4">中的font标志有size属性,表示size字体为4号字。格式信息正是通过标志和标志属性设置的。在IE浏览器下,上述HTML文件的浏览效果如图1-1所示。

图1-1 浏览器下查看HTML

从浏览效果来看,HTML文件提供了比较丰富的界面元素。其外观效果远非文本效果可以比拟。但HTML的内容都是静态准备好的,如果打算制作网页反映股票信息,实现这样的任务几乎是不可能的,因为股票信息时刻在变,而为了反映这种变化,就必须时刻重新编写HTML。为了解决动态信息的发布问题,活动服务页面ASP诞生了。

活动服务页面在HTML的基础上引入了一些额外的标志,这些标志指示服务器在返回用户请求的页面之前进行进一步的处理。对客户而言,它最终仍然会得到一个HTML文件,但该HTML文件是在服务器端动态生成的。对服务器而言,它要根据用户的请求把活动页面中的内容翻译成HTML代码,开发ASP应用工具有InterDev等。下面是一个ASP文件(demo.asp)的示例:

    <html>
    <head>
    <title>演示ASP</title>
    </head>
    <body>
        <% Response.Write("Hello," +Request("user")) %>
    </body>
    </html>

ASP文件跟HTML文件类似,也可以包括<html>等标志,但其中有一种特殊的<% %>标志,该标志指示期间的代码要在服务器上执行,执行的结果将作为HTML文件的一部分返回给客户。

其中Response对象是ASP内置的对象之一,表示对用户的回应,Response.Write方法用以向客户端写入回应消息。Request对象是另一个内置对象,表示用户的请求,例如通过该对象可以获得用户获取的Form表单(如果通过Post方法提交)或者通过Get方法提交请求时的参数。代码Request(“user”)表示获得Get参数列表中的user参数。

下面的命令用以请求demo.asp,并指定user参数为“晓华”:

http://localhost/demo.asp?user=晓华

浏览器的显示结果如图1-2所示。

图1-2 客户端浏览器显示请求响应

提示

响应返回的是HTML文档,该文档是由服务器动态构造的,其内容如下:

                      <html>
                      <head>
                      <title>演示ASP</title>
                      </head>
                      <body>
                          Hello,晓华
                      </body>
                      </html>

活动服务页面能根据用户的请求动态产生HTML文件,这是相对于静态HTML应用的一大进步。它即充分利用了HTML强大的显示功能,又充分表达了动态的信息,但ASP仍存在下面的不足:

● 界面和代码没有分开

ASP应用中的代码包含在界面元素之间,这样导致程序结构不清晰,增加了维护代码的难度。

● 解释性的脚本语言

ASP中所用到的编程语言是解释性的脚本语言,如VBScript或JScript。每次服务器响应客户的请求,都要调用某种语言引擎解释脚本代码,这样降低了程序的执行效率,会影响对客户的响应。

ASP.NET克服了ASP上述不足,利用Visual Studio.NET集成开发工具,开发人员甚至可以像设计Visual Basic程序那样开发ASP.NET应用。

通过一种所谓的隐藏代码技术,彻底实现了界面和代码分离。下面是一个利用Visual Studio.NET产生的空白页面示例,它由两部分组成,界面和代码,两部分都被保存为一个独立的文件。界面文件以.aspx为后缀,下面是其内容:

    [Visual Basic]
    <%@   Page   Language="vb"   AutoEventWireup="false"   Codebehind="WebForm1.aspx.vb"
Inherits="CH1.WebForm1"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <html>
        <head>
            <title>WebForm1</title>
            <meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.0">
            <meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
            <meta name="vs_defaultClientScript" content="JavaScript">
            <meta                                                name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
        </head>
        <body MS_POSITIONING="GridLayout">
            <form id="Form1" method="post" runat="server">
            </form>
        </body>
    </html>
    [C#]
    <%@   Page   language="c#"   Codebehind="WebForm1.aspx.cs"   AutoEventWireup="false"
Inherits="CSCH1.WebForm1" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
    <HTML>
        <HEAD>
            <title>WebForm1</title>
            <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
            <meta name="CODE_LANGUAGE" Content="C#">
            <meta name="vs_defaultClientScript" content="JavaScript">
            <meta                                                name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
        </HEAD>
        <body MS_POSITIONING="GridLayout">
            <form id="Form1" method="post" runat="server">
    98      </form>
        </body>
    </HTML>

首先注意.aspx文件的第一行,该行是一个页面Page指令。Language指示页面的编程语言,可以为C#、Visual Basic或任意一种.NET平台下的编程语言。Codebihand属性指示于界面元素关联的代码文件,Inherits属性用以指示当前页面的父类,AutoEventWireup属性指示是否在页面加载时,自动调用页面中定义的Page_Init和Page_Load方法。

提示

一个.aspx文件实际上隐含定义一个Page派生类,它们直接或间接地从Page类派生。

我们再看看代码隐藏文件,隐藏代码定义了一个页面类,它直接从System.Web.UI.Page派生。下面是其具体内容:

    [Visual Basic]
    Public Class WebForm1
        Inherits System.Web.UI.Page
    #Region"Web 窗体设计器生成的代码 "
        '该调用是 Web 窗体设计器所必需的。
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        End Sub
        Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles
MyBase.Init
            'CODEGEN: 此方法调用是 Web 窗体设计器所必需的。
            '不要使用代码编辑器修改它。
            InitializeComponent()
        End Sub
    #End Region
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
            '在此处放置初始化页的用户代码
        End Sub
    End Class
    [C#]
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Web;
    using System.Web.SessionState;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    namespace CSCH1
    {
                /// <summary>
                ///WebForm1 的摘要说明。
                /// </summary>
                public class WebForm1 : System.Web.UI.Page
                {
                    private void Page_Load(object sender, System.EventArgs e)
                    {
                        // 在此处放置用户代码以初始化页面
                        //Request.Form
                    }
                    #region Web Form Designer generated code
                    override protected void OnInit(EventArgs e)
                    {
                        //
                        //CODEGEN:该调用是 ASP.NET Web 窗体设计器所必需的。
                        //
                        InitializeComponent();
                        base.OnInit(e);
                    }
                    /// <summary>
                    /// 设计器支持所需的方法 - 不要使用代码编辑器修改
                    /// 此方法的内容。
                    /// </summary>
                    private void InitializeComponent()
                    {
                        this.Load += new System.EventHandler(this.Page_Load);
                    }
                    #endregion
                }
    }

如果读者有Visual Basic.NET或C#的编程经验,读懂上述代码应该没有任何问题。上述代码的主题是重载父类的OnInit方法和为Load事件添加处理代码。通过下面的方法挂钩事件:

[Visual Basic]

方法后跟Handlers关键字指示处理的事件,上例中的Page_Load方法即是一例。

提示

为了保证该方法正确的处理事件,必须保证该方法的签名符合事件类型。在Visual Basic中,事件类型用委托来定义,例如:Web窗体的Load事件由下面的委托定义:

                      <Serializable>
                      Public Delegate Sub EventHandler( _
                        ByVal sender As Object, _
                        ByVal e As EventArgs _
                      )

所以Page_Load方法的的第一个参数必须为Object类型,第二个参数必须为EventArgs类型,并且该方法无返回值(为过程)。

    [C#]

把委托实例跟事件直接挂钩。把本例中挂钩事件的处理代码重写如下:

                        this.Load += new System.EventHandler(this.Page_Load);

代码右边生成一个EventHandler委托实例。this.Page_Load方法的签名必须符合该委托。代码左边是要处理的事件(实际上是一个委托变量),运算符+=将左边的委托实例和右边的事件关联起来。

提示

C#中this关键字表示对象自身,而Visual Basic中对应的关键字是Me。

从上面的例子可以看出,ASP.NET真正实现了将代码和内容分开,已有的开发其他.NET应用的经验可以直接用到ASP.NET应用开发中来。

需要指出,代码隐藏文件并不是必须的,但利用它,可以将代码和界面分离,因此是一种值得推荐的做法。另外一种替换的编程方式跟传统的ASP应用开发类似,即把所有的代码和一些HTML标志元素混在一起,并保存为一个单独的文件(这样的文件仍以.aspx文为后缀)。下面是单文件的窗体示例:

    [Visual Basic]
    <html>
    <!--
      演示ASP.NET
    !-->
    <Script language="vb" runat="server">
        public sub Page_Load(sender as Object,  e as EventArgs)
            if not IsPostBack then
              Message.Text="Hello,World!"
            end if
        end sub
    </Script>
    <body>
      <h4><font face="verdana">
        <asp:Label id="Message" runat="server"/>
      </font></h4>
    </body>
    </html>
    [C#]
    <html>
    <!--
      演示ASP.NET
    !-->
    <Script language="C#" runat="server">
        public void Page_Load(Object sender, EventArgs e) {
            if(!IsPostBack)
              Message.Text="Hello,World!" ;
        }
    </Script>
    <body>
      <h4><font face="verdana">
        <asp:Label id="Message" runat="server"/>
      </font></h4>
    </body>
    </html>

观察上述文件,读者会注意到单文件的ASP.NET窗体跟以前的ASP非常类似,但仔细观察,你会发现Label控件前有asp命名控件限制,它表示Label为Web控件。ASP.NET页面引擎会根据Label控件的相关属性(例如Text属性)将它转化为适当的HTML代码。runat="server"表示该控件在服务端运行,也就是说由服务器将其翻译成HTML代码。

除了上述两点显而易见的好处之外,ASP.NET还增加了许多具有吸引力的新功能,大部分功能都是.NET框架特性的一部分。下面是列表是这些新功能的不完全清单:

● 状态视图

ASP.NET提供状态视图在页面的一个往返行程之间保存页面的状态。这就为开发人员提供了更多的选择:他们就可以使用传统的Session或Application对象保存状态或数据库在服务端保持页面状态,还可以状态视图在客户端保存页面状态。状态视图通过隐藏域实现,因此除了往返行程的流量开销外几乎没有其他限制。

● 一致的事件模型

处理Web窗体的事件就跟处理传统的Window窗体的事件类似。经过ASP.NET框架的精心包装,客户端(远程的浏览器)引发的事件可以透明传递到服务器,开发人员像处理本地事件一样处理这些事件。

Web窗体中的事件处理也是基于委托的,委托相当于一个智能的函数指针。Web窗体的事件和本机窗口事件都表示为委托,并通过实例化委托将事件和事件处理代码挂钩。

● 基于XML文件的配置

可以为任何ASP.NET应用编写一个XML文件格式的配置文件。利用配置文件,可以方便地设置ASP.NET应用的安全性、进程模型、语言编码等。

开发人员可以随时添加或修改配置设置,但同时,ASP.NET框架可以保证这种修改对运作着的Web应用程序和服务器产生最小的影响。

● 灵活地使用任何组件

因为ASP.NET应用最终被编译成程序集,所以可以使用.NET框架类库中的任何组件。而程序员要做的只是添加对程序集的引用和引入命名空间。

以往的COM组件也可以继续使用,但在使用之前,它们通过.NET框架提供的互操作服务转化为互操作程序集。

提示

在使用COM组件的背后,会发生很多事情,但集成开发工具使得程序员可以通过添加引用的方式使用任何COM对象。

利用集成开发环境,可以向ASP.NETWeb应用中添加各种编程元素,例如窗体、类、样式等,如图1-3所示。

图1-3 集成开发环境下向Web应用中添加各种编程元素

● 支持Web服务

Web服务是基于一系列开发标准之上的可通过Web调用的功能。它把整个网络变成一个可编程的计算平台。ASP.NET支持创建基于XML的Web服务,并可以方便地使用Web服务。

1.2 开发之前

在开始我们的第一个ASP.NET应用之前,笔者还希望读者了解下面一些问题。

第一个问题是:选用何种编程语言。跟前期的ASP不同,现在的ASP.NET应用可以用任何适用于.NET框架的编程语言。这样读者可选择的范围就扩大了,例如C#、Visual Basic、托管C++、JScript等。本质上,这些语言只有语法上的差异,因为它们最终都编译成微软中间代码,所以,选用何种语言完全取决于个人的爱好。如果读者是一位新手,建议使用C#语言,该语言是.NET平台下的标准编程语言。而对以往的VBScript程序员可能会选择Visual Basic,因为以往的经验可以缩短他们了解Visual Basic.NET语言所花的时间。

如果用集成开发环境开发ASP.NET应用,那么整个项目中的所有隐藏代码只能采取同一种编程语言。因为同一个项目中的所有这些文件要被同一个编译器编译成一个程序集。

提示

配置文件中用下面的代码来规定默认的编程语言。

                      <compilation defaultLanguage="vb" />

另外,每个页面也可以用Page指令设定编程语言。例如:

    <%@ Page Language="vb" "%>

如果不指定Page的Language属性,那么将采用在配置文件中的默认设置。

提示

利用Page指令的Language属性,可以单独设置.aspx文件中的编程语言,同一个页面只能设置成一种编程语言,如下面的代码:

                      <%@ Page Language="cs" AutoEventWireup="false" %>
                      <HTML>
                      <body MS_POSITIONING="GridLayout">
                      <form id="Form1" method="post" runat="server">
                        <FONT face="宋体">
                          <asp:Label id="Label1" style="Z-INDEX: 101; LEFT: 172px; POSITION:
                  absolute;       TOP:       90px"       runat="server"       Width="256px"
                  Height="53px">Label</asp:Label></FONT>
                          </form>
                          <Script language=vb  runat="server"id="Script1">
                              Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
                  System.EventArgs) Handles MyBase.Load
                                    '在此处放置初始化页的用户代码
                                    if not IsPostBack then
                                        Label1.Text="Hello"
                                    end if
                                  End Sub
                          </Script>
                      </body>
                      </HTML>

把上述文件保存到wwwroot目录下的demo2.aspx文件下,然后启动浏览器执行http://localhost/demo2.aspx,执行结果如图1-4所示。

图1-4 执行结果

为了解决这个问题,请把第一行中的代码修改为:

    <%@ Page Language="vb" AutoEventWireup="false" %>

第二个问题是:选用何种编程工具。目前开发ASP.NET应用最好的工具就是Visual Studio.NET,它提供了Web窗体设计器,并支持隐藏代码模型。利用它可以快速地开发出ASP.NET应用,而不用关心实现的细节,但目前Visual Studio.NET对单文件的.aspx撰写提供的支持还非常有限。例如,不支持.aspx文件中的代码高亮度显示,没有智能提示等。

第三个问题是:关于学习ASP.NET应用开发的最佳方法是什么。一般而言,按照本书安排的学习顺序,读者将能完全掌握ASP.NET应用开发技术,但为了获得更好的学习效果,下面的一些建议可能是有益的。

● 熟悉选用的编程语言

本书的目的不是向大家介绍编程语言。如果读者决定用Visual Basic或C#等语言开发ASP.NET应用,那么就要花一些时间来熟悉这些语言,主要是属性常见的语句,例如类型定义、变量声明、循环、分支等。读者可以参考本社已出版的《Visual Basic.NET编程指南》一书和《C#编程指南》中的第2章,从中获得有关编程语言本身的知识。

● 熟悉常见.NET框架类库

.NET框架类库为所有的.NET应用共有,ASP.NET应用也不例外。了解常用的.NET框架类,例如集合、数组、字符串等,无疑可以提高ASP.NET应用开发水平,并能更好地理解本书中所有的范例。

1.3 第一个ASP.NET应用

将要开发的ASP.NET应用所演示的技术在开发实际站点时经常用到——用户登录,并验证用户的身份,以确保只有特定的用户才能访问本应用(本例设定为只有晓华输入正确的口令“1234”时,才可访问本应用)。下面将详细描述该应用的实现步骤。

1.3.1 第一步:新建一个ASP.NET应用

将其位置设定为:

    [Visual Basic]
    http://localhost/DEMO/CH1
    [C#]
    http://localhost/DEMOCS/CH1

执行结果如图1-5所示。

图1-5 新建ASP.NET应用

1.3.2 第二步:检查生成的文件

请切换到项目资源视图,以查看项目下的所有文件,如图1-6所示。

图1-6 生成的文件

各个文件的功能和内容分别介绍如下:

● 应用配置文件

web.config文件是ASP.NET应用配置文件,其内容如下,其中的注释说明了每个配置元素的含义。本书后续章节将对每个配置元素做详细讲解。

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.web>
        <!--        动态调试编译
                    设置  compilation debug="true" 以启用  .aspx 调试。否则,将此值设置为
false,将提高此应用程序的运行时性能。
                    设置 compilation debug="true" 以将调试符号(.pdb 信息)
                    插入到编译页中。因为这将创建执行起来
                    较慢的大文件,所以应该只在调试时将该值设置为 true,而在其他的时候都设置为
false。有关更多信息,请参考有关调试 ASP.NET 文件的文档。
        -->
        <!--
                    设置默认的编程语言,如果选择建立Visual Basic语言的ASP.NET应用,则
                    defaultLanguage="vb"
        -->
        <compilation
                    defaultLanguage="c#"
                    debug="true"
        />
        <!--        自定义错误信息
                    设置 customError 模式值可以控制应向
                    用户显示用户友好错误信息而不是错误详细信息:
                    “On”始终显示自定义(友好的)信息。
                    “Off”始终显示详细的 ASP.NET 错误信息。
                    “RemoteOnly”只对不在本地 Web 服务器上运行的
                    用户显示自定义(友好的)信息。出于安全目的,建议使用此设置,以便
                    不向远程客户端显示应用程序的详细信息。
        -->
        <customErrors
        mode="RemoteOnly"
        />
        <!--        身份验证
                    此节设置应用程序的身份验证策略。可能的模式是“Windows”、“Forms”、
                    “Passport”和“None”
        -->
        <authentication mode="Windows" />
        <!--        应用程序级别跟踪记录
                    应用程序级别跟踪在应用程序内为每一页启用跟踪日志输出。
                    设置 trace enabled="true" 以启用应用程序跟踪记录。如果 pageOutput="true",则
                    跟踪信息将显示在每一页的底部。否则,可以通过从 Web 应用程序
                    和浏览 "trace.axd" 页来查看应用程序跟踪日志。
        -->
        <trace
            enabled="false"
            requestLimit="10"
            pageOutput="false"
            traceMode="SortByTime"
                    localOnly="true"
        />
        <!--        会话状态设置
                    默认情况下,ASP.NET 使用Cookie 标识哪些请求属于特定的会话。
                    如果 Cookie 不可用,则可以通过将会话标识符添加到 URL_来跟踪会话。
                    若要禁用 Cookie,请设置 sessionState Cookieless="true"。
        -->
        <sessionState
                      mode="InProc"
                      stateConnectionString="tcpip=127.0.0.1:42424"
                      sqlConnectionString="data source=127.0.0.1;user id=sa;password="
                      Cookieless="false"
                      timeout="20"
        />
        <!--        全球化
                    此节设置应用程序的全球化设置。
        -->
        <globalization
                      requestEncoding="utf-8"
                      responseEncoding="utf-8"
          />
      </system.web>
    </configuration>

● 窗体文件

窗体文件包括以.aspx为后缀的界面文件和代码隐藏文件。

● Global.asax文件

它定义一些跟ASP.NET应用相关的全局变量。其典型用途是定义ASP.NET应用启动和结束、一个会话启动和结束时的响应函数。下面的代码清单可以非常清楚地看出Global.asax文件的作用。

    [Visual Basic]
    Imports System.Web
    Imports System.Web.SessionState
    Public Class Global
        Inherits System.Web.HTTPApplication
    #Region" 组件设计器生成的代码 "
        Public Sub New()
            MyBase.New()
            '该调用是组件设计器所必需的。
            InitializeComponent()
            '在 InitializeComponent() 调用之后添加任何初始化
        End Sub
        '组件设计器所必需的
        Private components As System.ComponentModel.IContainer
        '注意:以下过程是组件设计器所必需的
        '可以使用组件设计器修改此过程。
        '不要使用代码编辑器修改它。
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            components = New System.ComponentModel.Container()
        End Sub
    #End Region
        Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
            ' 在应用程序启动时激发
        End Sub
        Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
            ' 在会话启动时激发
        End Sub
        Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
            ' 在每个请求开始时激发
        End Sub
        Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
            ' 尝试对使用进行身份验证时激发
        End Sub
        Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
            ' 在发生错误时激发
        End Sub
        Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
            ' 在会话结束时激发
        End Sub
        Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
            ' 在应用程序结束时激发
        End Sub
    End Class
    [C#]
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Web;
    using System.Web.SessionState;
    namespace CSCH1
    {
    /// <summary>
    ///Global 的摘要说明。
    /// </summary>
    public class Global : System.Web.HTTPApplication
    {
          public Global()
          {
              InitializeComponent();
          }
          protected void Application_Start(Object sender, EventArgs e)
          {
          }
          protected void Session_Start(Object sender, EventArgs e)
          {
          }
          protected void Application_BeginRequest(Object sender, EventArgs e)
          {
          }
          protected void Application_EndRequest(Object sender, EventArgs e)
          {
          }
          protected void Application_AuthenticateRequest(Object sender, EventArgs e)
          {
          }
          protected void Application_Error(Object sender, EventArgs e)
          {
          }
          protected void Session_End(Object sender, EventArgs e)
          {
          }
          protected void Application_End(Object sender, EventArgs e)
          {
          }
          #region Web Form Designer generated code
            ///<summary>
            /// 设计器支持所需的方法 - 不要使用代码编辑器修改
            /// 此方法的内容。
            ///</summary>
          private void InitializeComponent()
          {
          }
          #endregion

在本书后续章节将详细讨论如何编写上述清单中的各个方法。

● Styles.css文件

新Web应用程序项目的默认CSS样式表,使用样式的好处是省去了为每个标志设置属性的麻烦。样式的定义语法为:

元素名称{样式名:值;样式名:值…}

下面是该文件中定义的若干样式类:

    BODY
    {
        BACKGROUND-COLOR: white;
        FONT-FAMILY: Verdana, Helvetica, sans-serif;
        FONT-SIZE: .8em;
        FONT-WEIGHT: normal;
        LETTER-SPACING: normal;
        TEXT-TRANSFORM: none;
        WORD-SPACING: normal
    }
    H1, H2, H3, H4, H5, TH, THEAD, TFOOT
    {
        COLOR: #003366;
    }
    H1  {
        font-family:Verdana,Arial,Helvetica,sans-serif;
        font-size:  2em;
        font-weight:     700;
        font-style: normal;
        text-decoration: none;
    word-spacing:        normal;
        letter-spacing:  normal;
        text-transform:  none;
        }
    IMG     {
    margin-top: 5px;
    margin-left: 10px;
    margin-right: 10px;
        }

如果为.aspx文件指定了应用上述样式,那么<body>标志内的HTML元素自动以下面的设置为默认值:

BACKGROUND-COLOR: white;

FONT-FAMILY: Verdana, Helvetica, sans-serif;

FONT-SIZE: .8em;

FONT-WEIGHT: normal;

LETTER-SPACING: normal;

TEXT-TRANSFORM: none;

WORD-SPACING: normal

但如果对<body>内的某个子元素重新设置了相应的属性,例如“FONT-SIZE”,那么以新设置的属性为主。为了具体说明样式的作用效果和规则,我们在项目中添加一个名为democss.html的超文本文件,其内容如下:

    <html>
    <head>
          <link ref="stysheet" href="styles.css" type="text/css"></link>
    </head>
    <body>
          <h1>使用默认样式的效果</h1>
          <h1 style="color:red;font-size:20pt">
          定制的样式覆盖了默认样式中的文字颜色和大小
          </h1>
    </body>
    </html>

浏览器中的浏览效果如图1-7所示。

图1-7 使用样式后的浏览效果

<body>内的第一个<h1>元素采用<body>和<h1>中的默认属性,而第二个<h2>重写了文字颜色和大小两个属性。

其中第三句代码用以引用外部设定的样式文件,还可以使用内嵌的样式,这时样式在<style>标志内定义,例如:

    <html>
        <head>
            <!--
            <link ref="stysheet" href="styles.css" type="text/css"></link>
            -->
            <style>
                BODY
                {
                    BACKGROUND-COLOR: white;
                    FONT-FAMILY: Verdana, Helvetica, sans-serif;
                    FONT-SIZE: .8em;
                    FONT-WEIGHT: normal;
                    LETTER-SPACING: normal;
                    TEXT-TRANSFORM: none;
                    WORD-SPACING: normal
                }
                H1, H2, H3, H4, H5, TH, THEAD, TFOOT
                {
                    COLOR: #003366;
                }
                H1
                {
                    font-family: Verdana, Arial, Helvetica, sans-serif;
                    font-size:  2em;
                    font-weight:     700;
                    font-style: normal;
                    text-decoration: none;
                    word-spacing:    normal;
                    letter-spacing:  normal;
                    text-transform:  none;
                }
        </style>
        </head>
        <body>
            <h1>使用默认样式的效果</h1>
            <h1 style="color:red;font-size:20pt">
                定制的样式覆盖了默认样式中的文字颜色和大小
            </h1>
        </body>
    </html>

● 程序集信息文件

隐藏代码被编译为一个程序集。程序集信息文件设置该程序集的若干信息,如版本、区域性、密钥文件等。

    [Visual Basic]
    Imports System.Reflection
    Imports System.Runtime.InteropServices
    ' 程序集的常规信息通过下列
    ' 属性集控制。更改这些属性值可
    ' 修改与程序集关联的信息。
    ' 检查程序集的属性值
    <Assembly: AssemblyTitle("")>
    <Assembly: AssemblyDeScription("")>
    <Assembly: AssemblyCompany("")>
    <Assembly: AssemblyProduct("")>
    <Assembly: AssemblyCopyright("")>
    <Assembly: AssemblyTrademark("")>
    <Assembly: CLSCompliant(True)>
    '如果该项目向 COM 公开,则下列 GUID 用于类型库的 ID
    <Assembly: Guid("FF8D28EA-4294-4189-924A-FF51319DB917")>
    ' 程序集的版本信息由下列 4 个值组成:
    '
    '      主版本
    '      次版本
    '      内部版本号
    '      修订号
    '
    ' 您可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,方法是按
    ' 如下所示使用“*”:
    <Assembly: AssemblyVersion("1.0.*")>
    [C#]
    using System.Reflection;
    using System.Runtime.CompilerServices;
    //
    // 有关程序集的常规信息是通过下列
    //属性集控制的。更改这些属性值可修改与程序集
    //关联的信息。
    //
    [assembly: AssemblyTitle("")]
    [assembly: AssemblyDeScription("")]
    [assembly: AssemblyConfiguration("")]
    [assembly: AssemblyCompany("")]
    [assembly: AssemblyProduct("")]
    [assembly: AssemblyCopyright("")]
    [assembly: AssemblyTrademark("")]
    [assembly: AssemblyCulture("")]
    //
    // 程序集的版本信息包含下列 4 个值:
    //
    //     主版本
    //     次版本
    //     内部版本号
    //     修订号
    //
    // 您可以指定所有值,或使用“修订号”和“内部版本号”的默认值,方法为按如下方式
    // 使用“*”:
    [assembly: AssemblyVersion("1.0.*")]
    //
    // 要对程序集进行签名,必须指定要使用的密钥。有关程序集签名的更多信息,请参考
    //Microsoft.NET 框架文档。
    //
    // 使用下面的属性控制用于签名的密钥。
    //
    // 注意:
    //   (*) 如果未指定密钥,则程序集不会被签名。
    //   (*)KeyName 是指已经安装在
    //       计算机上的加密服务提供程序 (CSP) 中的密钥。KeyFile 是指包含
    //       密钥的文件。
    //   (*) 如果 KeyFile 和 KeyName 值都已指定,则发生下面的处理:
    //       (1) 如果在 CSP 中可以找到 KeyName,则使用该密钥。
    //       (2) 如果 KeyName 不存在而 KeyFile 存在,则
    //          KeyFile 中的密钥安装到 CSP 中并且使用该密钥。
    //   (*) 要创建 KeyFile,可以使用 sn.exe(强名称)实用工具。
    //       在指定 KeyFile 时,KeyFile 的位置应该
    //       相对于“项目输出目录”。项目输出
    //       目录的位置取决于您是在使用本地项目还是 Web 项目。
    //       对于本地项目,项目输出目录定义为
    //       <Project Directory>\obj\<Configuration>。例如,如果 KeyFile 位于该
    //       项目目录中,应将 AssemblyKeyFile
    //       属性指定为 [assembly:AssemblyKeyFile("..\\..\\mykey.snk")]
    //       对于 Web 项目,项目输出目录定义为
    //   %HOMEPATH%\VSWebCache\<Machine Name>\<Project Directory>\obj\<Configuration>。
    //   (*)“延迟签名”是一个高级选项 - 有关它的更多信息,请参阅 Microsoft.NET 框架文档。
    //
    [assembly: AssemblyDelaySign(false)]
    [assembly: AssemblyKeyFile("")]
    [assembly: AssemblyKeyName("")]

提示

上述文件主要是利用程序集层次的相关特性来设置程序集的属性。特性是.NET框架提供的功能,用以对程序集作批注,例如可以用Assembly层次上的AssemblyVersion特性设置程序集版本:

              [Visual Basic]
              <Assembly: AssemblyVersion("1.0.*")>
                      [C#]
                      [assembly: AssemblyVersion("1.0.*")]

其中参数“1.0.*.*”是Assembly: AssemblyVersion特性的占位参数(也就是AssemblyVersion特性类构造函数中的一个参数)。

1.3.3 第三步:设计WebForm1窗体

把WebForm1窗体设计成一个如图1-8所示的登录界面。

图1-8 设计好的登录界面

图1-8中各个标号所指的控件分别是:

①和②是Web窗体下的标签控件,将①、②所指的标签分别设置为“用户名”和“口令”。

提示

Web控件的属性不同于HTML元素的属性。ASP.NET框架根据Web控件的属性设置转化为相应的HTML标志并设置其属性。

③所指的为Web按钮控件,将其Text属性设置为“提交”。

④所指的为Web验证汇总控件ValidationSummary,将其属性保持为默认值。

⑤所指的是Web文本框TextBox控件,将其ID属性设置为username。

提示

代码中通过ID引用相应的属性。

⑥所指的是HTML口令Password控件,将其ID属性设置为pwd。然后选中该控件,单击右键,单击【作为服务器控件运行】按钮,如图1-9所示。

图1-9 将HTML控件设置为作为服务器控件运行

说明

默认情况下,HTML控件作为客户端控件运行,这样服务端的代码就不用通过其ID引用该控件。转化为服务器端控件运行后,自动将其runat属性设置为server。

⑦所指的是Web必须域RequiredFieldValidator验证控件,将其Text属性设置为“*”,将其ErrorMessage属性设置为“用户名不能为空”,将其ControlToValidate属性设置为⑤所指的文本框控件的ID“username”。

提示

RequiredFieldValidator验证控件验证其ControlToValidate属性所指的控件的值是否为空,如果为空,则将显示其Text属性所设的值,同时向验证汇总控件ValidationSummary中添加一条由其ErrorMessage所指的错误消息。

⑧所指的也是Web必须域RequiredFieldValidator验证控件,将其Text属性设置为“*”,将其ErrorMessage属性设置为“口令不能为空”,将其ControlToValidate属性设置为⑥所指的文本框控件的ID“pwd”。

提示

在窗体的设计视图下,图1-9中所有的控件都可以从工具箱中拖放到窗体上。Web控件位于工具箱的“Web窗体”页下,HTML控件则位于“HTML”页下。

切换到HTML视图下,可以查看Web窗体的代码。本例中设计完成后的窗体具有下面清单所示的代码:

    <%@ Page Language="cs" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb" Inherits=
"CH1.WebForm1"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
                <HEAD>
                    <title>WebForm1</title>
                    <meta content="Microsoft Visual Studio.NET 7.0"name="GENERATOR">
                    <meta content="Visual Basic 7.0"name="CODE_LANGUAGE">
                    <meta content="JavaScript"name="vs_defaultClientScript">
                    <meta                            content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
                </HEAD>
                <body MS_POSITIONING="GridLayout">
                    <form id="Form1"method="post"runat="server">
                           <FONT face="宋体">
                            <asp:label id="Label1" style="Z-INDEX: 101; LEFT: 63px; POSITION:
absolute;   TOP:   41px"      runat="server"   Width="68px"            Height="24px">   用  户  名
</asp:label><asp:requiredfieldvalidator  id="RequiredFieldValidator2"  style="Z-INDEX:  106;  LEFT:
382px;  POSITION:  absolute;  TOP:  96px"  runat="server"  ErrorMessage=" 口 令 不 能 为 空 "
ControlToValidate="pwd">*</asp:requiredfieldvalidator><asp:label id="Label2" style="Z-INDEX: 103;
LEFT: 65px; POSITION: absolute; TOP: 98px" runat="server" Width="68px" Height="24px">口令
</asp:label>
                            <asp:TextBox  id="username"  style="Z-INDEX:  102;        LEFT:         156px;
POSITION:absolute;TOP:36px"runat="server"Width="201px"Height="30px"></asp:TextBox>
                            <INPUT id="pwd" style="Z-INDEX: 104; LEFT: 152px; POSITION:
absolute;TOP:97px"type="password"name="Password1"runat="server">&nbsp;
                            <asp:RequiredFieldValidator id="RequiredFieldValidator1" style="Z-INDEX:
105; LEFT: 381px; POSITION: absolute; TOP: 39px" runat="server" ErrorMessage="用户名不能为空"
ControlToValidate="username"Display="None">*</asp:RequiredFieldValidator>
                            <asp:ValidationSummary id="ValidationSummary1" style="Z-INDEX: 107;
        LEFT:   74px;   POSITION:   absolute;        TOP:   216px"   runat="server"   Width="228px"
        Height="36px"></asp:ValidationSummary>
                            <asp:Button id="Button1" style="Z-INDEX: 108; LEFT: 75px; POSITION:
absolute;   TOP:   149px"   runat="server"   Width="313px"   Height="32px"   Text="         提  交
"></asp:Button></FONT></form>
                </body>
    </HTML>

说明

上面清单只列出了编程语言为Visual Basic的窗体界面代码。如果编程语言为C#,那么把设置特定语言的代码中的“vb”替换为“cs”(或C#)即可。

1.3.4 第四步:编码

双击WebForm1上的按钮控件,ASP.NET自动在代码隐藏文件中添加处理按钮控件事件的代码框架。

    [Visual Basic]
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
        End Sub
    [C#]
                    private void Button1_Click(object sender, System.EventArgs e)
                    {
                    }说明

Web窗体设计器还自动在InitializeComponent方法中添加挂钩事件的代码:

                          this.Button1.Click += new System.EventHandler(this.Button1_Click);

然后在Button1_Click函数体内输入下面的代码:

    [Visual Basic]
          If username.Text = "晓华" And pwd.Value = "1234" Then
              FormsAuthentication.RedirectFromLoginPage("晓华", True)
          Else
              Response.Redirect("webform1.aspx")
          End If
    [C#]
            if(username.Text == "晓华" && pwd.Value == "1234" )
            {
                FormsAuthentication.RedirectFromLoginPage("晓华", true);
            }
          else
                Response.Redirect("webform1.aspx");

上述代码判断用户是否是特定的用户(用户名为“晓华”,口令为“1234”),如果是则在客户端生成标志用户身份的Coockie,并定位到请求的网页。否则将重定向到登录界面。

为了顺利编译上述代码,请引入FormsAuthentication所在的命名空间:

    [Visual Basic]
    Imports System.Web.Security
    [C#]
    using System.Web.Security;

说明

FormsAuthentication.RedirectFromLoginPage将已验证身份的用户重定向最初请求的URL。第一个参数表示用于Cookie身份验证的用户名称,该名称不必是Windows系统中的账户。第二个参数指示是应当发出持久性Cookie。

如果没有指定请求的网页(例如本例中通过点击按钮提交WebForm1窗体就是如此),那么FormsAuthentication.RedirectFromLoginPage将重定向到Default.aspx。正是这个原因,稍后我们要往项目中添加一个名为Default.aspx的窗体。

Response.Redirect方法将结果导到指定的网页作为回应。Web窗体的Response属性封装了跟客户端的响应相关的操作。

1.3.5 第五步:添加Default.aspx窗体

在资源管理器视图下,选中ASP.NET应用项目,单击右键,指向【添加Web窗体】,在弹出的子菜单中单击【添加】按钮,如图1-10所示。

图1-10 添加Web窗体的菜单

这时会弹出如图1-11所示的“添加新项”对话框,将新建的窗体命名为Default.aspx,然后单击【打开】按钮。

图1-11 “添加新项”对话框

这时添加的DefaultWeb窗体处于设计视图下,按照如图1-12所示设计其界面。

图1-12 设计DefaultWeb窗体的界面

DefaultWeb窗体上包含了一个Web标签控件和一个Web按钮控件。

然后双击按钮,添加处理按钮单击的代码:

    [Visual Basic]
              Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
      Handles Button1.Click
                  FormsAuthentication.SignOut()
              End Sub
    [C#]
                    private void Button1_Click(object sender, System.EventArgs e)
                    {
                        FormsAuthentication.SignOut();
                    }

同样在代码隐藏文件的开头引入FormsAuthentication所在的命名空间:

    [Visual Basic]
    Imports System.Web.Security
    [C#]
    using System.Web.Security;

FormsAuthentication.SignOut方法移除身份验证凭据,调用后,客户端表示用户身份的持久性Cookie或会话Cookie将被删除。

1.3.6 第六步:配置

双击web.config文件,找到下面的代码:

    <authentication mode="Windows" />

用下面的代码替换上面的代码:

                  <authentication mode="Forms">
                    <forms loginURL="webform1.aspx" />
                  </authentication>

上述配置的含义是将验证模式设置为窗体验证模式,并设置登录窗体为webform1.aspx。窗体验证模式允许ASP.NETWeb应用通过窗体收集用户的信息,并验证用户是否合法。

然后找到<authorization></authorization>元素,用下面的内容替换该元素及其内部的代码:

              <authorization>
                  <deny users="?" />
              </authorization>

<deny users="?" />禁止没有通过身份验证的用户访问本Web应用程序。

1.3.7 第七步:测试

按【Ctrl+Shift+B】键编译项目,然后按【Ctrl+F5】键运行程序。

说明

ASP.NET应用的隐藏代码在执行前要被编译成程序集,对ASP应用开发比较熟悉的读者一定要注意这一点。直接按【Ctrl+F5】键,在执行之前要先编译项目,然后执行项目的启动页面。

读者可能会对集成开发工具具体的编译过程感到好奇。在用户发出编译命令后,集成开发环境将调用特定编程语言的编译器(Visual Basic为vbc.exe、C#为csc.exe)把项目中的隐藏代码文件编译成一个DLL形式的程序集(也叫类库),生成后的程序集位于应用程序根目录下的bin子目录下。默认情况下,生成的程序集的名字跟项目名相同,但可以通过设置项目的相关属性改变。改变的方法是在项目资源管理器视图下单击要设置的项目,单击鼠标右键,单击【属性】按钮,这时会弹出项目的“属性”对话框。展开【通用属性】节点,单击【常规】子项,就出现如图1-13所示(如果项目的编程语言为C#,则对应的画面如图1-14所示)的画面,在该画面下可以设置程序集的名称。

图1-13 设置项目输出的程序集(Visual Basic)

图1-14 设置项目输出的程序集(C#)

在介绍ASP.NET Web应用部署的时候,我们将进一步介绍相关的编译命令vbc.exe和csc.exe。现在大家只要知道,ASP.NET Web应用可以引用位于bin子目录下的程序集就够了。

可以引用某个程序集的含义是可以使用该程序集内实现的各种类型。程序集包含了它依赖的其他程序集的信息,以及其中定义的所有类型的信息,这些信息叫做程序集清单。为了使用某个程序集实现的组件,不用注册该组件,直接将该程序集拷贝到bin子目录下即可。

提示

bin子目下的程序集是ASP.NET Web应用的专用程序集。某些情况下,可能希望同一个程序集内的组件被多个ASP.NET Web应用(或其他类型的.NET应用,如本地窗体应用、控制台应用等),那么可以将该组件转化为强名程序集,并将之放入全局程序集缓存,这样的程序集叫做共享程序集。.NET应用不必在私有的库目录(对ASP.NET Web应用而言,该目录是BIN子目录)保存共享程序集的拷贝。大家可能注意到,.NET框架类库就是共享的程序集,这些程序集都有强名字并被预先放入了全局程序集缓存,所以ASP.NET Web应用可以自由引用.NET框架库,而不会在bin子目录下保存它们的副本。

程序集是.NET应用的核心,多花些时间深入了解程序集是值得的。本书后面介绍ASP.NET Web应用的部署的时候将会对程序集做进一步介绍。

隐藏代码在运行之前就编译成了bin子目录下的程序集,那么Web窗体的界面元素文件(后缀为.aspx的文件)又如何呢?答案是在第一次请求.aspx文件时,该文件被动态编译成程序集,该程序集实现一个从代码隐藏类实现的Web窗体的派生类。我们在回头看看webform1.aspx文件的第一行代码:

    [Visual Basic]
    <%@   Page   Language="vb"   AutoEventWireup="false"   Codebehind="WebForm1.aspx.vb"
Inherits="CH1.WebForm1"%>
    [C#]
    <%@   Page   Language="cs"   AutoEventWireup="false"   Codebehind="WebForm1.aspx.cs"
Inherits="CH1.WebForm1"%>

其中Inherits属性就指定了本页面的父类,而其中的Codebehind只是用来把界面元素和隐藏代码关联起来,只在编辑代码时候起到同步界面视图和隐藏代码的作用,对最后的.aspx文件及隐藏代码文件的编译并没有影响。读者可以试着删除代码中的Codebehind属性设置,应该会发现代码运行后没有任何不同。

上面讨论的内容是为了帮助读者了解一些内幕信息。这样对程序设计过程中不致于被出现的一些意外所惑。顺便提一下,程序集中的代码是一种所谓的微软中间代码(MSIL),不能直接在CPUT上执行,但.NET运行时,提供的即时编译JIT技术能够动态地把MSIL转化为可被特定的CPU(例如X86芯片)执行的二进制代码。转化后的二进制代码将被缓存,并可以在响应后续请求时直接在CPU上运行。

上面的讨论实质上揭示了一个ASP.NET应用被编译直至运行过程中涉及的一些底层细节。本书后续章节将会对这些内容做进一步的探讨。下面回到测试的主题上来,运行项目后,将出现如图1-15所示的登录画面。

图1-15 登录画面

先实验一下必须域验证的效果。保持用户名和口令为空,直接单击【提交】按钮,将出现如图1-16所示的画面。因为必须域验证控件检查到输入用户名和口令中输入为空,从而显示提示文本(由其Text属性设定),并且错误信息(由验证控件的ErrorMessage属性设置)出现在验证汇总控件中。

图1-16 验证未通过

从执行结果可以看出,通过使用相关的验证控件,可以保证提交到服务器上的数据为有效数据。如果输入了无效数据,验证将不能通过,这时原来提交的请求页面,以及添加了若干验证信息的页面被返回。

在用户名文本框中输入“晓华”,再单击【提交】按钮,执行结果如图1-17所示。从执行结果可以看出,验证提示信息变化了,因为只有口令为空,而输入的用户名则在往返行程中保持不变。

图1-17 保持口令为空时的验证结果

在口令框中输入口令“1234”后,单击【提交】按钮,将弹出如图1-18所示的画面。弹出的“自动完成”对话框提示是否根据用户名文本框自动设置口令框中的口令,单击【否】继续。

图1-18 提示是否自动完成

这时将返回默认页面default.aspx的执行结果,如图1-19所示。服务器端将在客户端设置标志用户“晓华”身份的Coockie。

图1-19 成功登录后的画面

在图1-19中单击【Sign Out】按钮,将在客户端取消标志用户“晓华”身份的Coockie。如果试图不经过登录界面直接请求default.aspx页面,则ASP.NET框架首先验证用户的身份;如果客户端标志用户的Coockie,则把用户当成未经身份验证的匿名用户,而本示例通过配置文件中授权设置<deny users="?" />拒绝匿名用户的访问请求,并自动重定向到身份验证配置部分的Forms元素的loginURL属性设定的登录页面。

提示

如果客户端已经有了标志用户晓华身份的Coockie,则可以直接获得请求的页面。

从上面的测试可以看出,本示例中设计的登录界面的确保证了只有特定的用户才能成功登录,任何不经身份验证而直接获取本应用的请求都将失败。

注意

身份验证本身不能提供任何安全措施,安全的实施是通过对用户的授权实现的。本示例中,如果允许所有的用户都能登录,也就是在web.config文件的授权部分添加<deny users="?" />,那么任何用户都可以直接请求default.aspx。当然对webform1.aspx页面而言,仍然只有当用户名为“晓华”,口令为“1234”时,才会进入default.aspx页面,但这种设防已经毫无意义!

提示

可以在default.aspx页面内显示当前登录的用户名,这时请打开default.aspx的隐藏代码文件,并把Page_Load方法的代码修改为:

                      [Visual Basic]
                          Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
                  System.EventArgs) Handles MyBase.Load
                              '在此处放置初始化页的用户代码
                              If Not IsPostBack Then
                                  Label1.Text = User.Identity.Name & ",欢迎光临"
                              End If
                          End Sub
                      [C#]
                                private void Page_Load(object sender, System.EventArgs e)
                                {
                                    // 在此处放置用户代码以初始化页面
                                    Label1.Text = User.Identity.Name + ",欢迎光临";
                          }

其中,User.Identity获得当前用户的标志。

1.3.8 第八步:功能完善

上面示例仅允许一个特定的用户登录,假设随着程序的运行,需要允许更多的用户例如小杨等人也可以登录,那么就必须修改webform1.aspx的提交按钮的处理代码:

    [Visual Basic]
    If (username.Text = "晓华" And pwd.Value = "1234") Or (username.Text = "小杨" And pwd.Value =
"5157")  Then
    ‘…
    end if
    [C#]
    if((username.Text=="晓华"&&pwd.Value=="1234")||        (username.Text=="小杨"&&
pwd.Value == "5157" ))
    {
    }

随着允许访问的用户名单的增加,上述代码还会进一步增加,因此必须考虑另外一种更一般的方法。答案在于FormsAuthentication.Authenticate方法,它接收两个分别表示用户名和口令的参数,并根据配置文件中的身份验证节中的配置信息验证用户的身份。为了支持“晓华”和“小杨”两个用户登录,可以把web.config中配置身份验证的部分修改为如下所示:

                  <authentication mode="Forms">
                    <forms loginURL="webform1.aspx">
                      <credentials passwordFormat = "Clear" >
                          <user name="小杨" password="5157"/>
                          <user name="晓华" password="1234"/>
                      </credentials>
                      </forms>
                  </authentication>

credentials元素的passwordFormat属性设置为Clear,表示用户的密码用明文表示,因此用户“小杨”的密码就是“5157”,用户“晓华”的密码就是“1234”。

注意

passwordFormat属性区分大小写,不要把Clear误写为clear。

然后把webform1的提交按钮的单击事件处理代码修改为如下所示:

    [Visual Basic]
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
            If FormsAuthentication.Authenticate(username.Text, pwd.Value) Then
                FormsAuthentication.RedirectFromLoginPage(username.Text, True)
            Else
                Response.Redirect("webform1.aspx")
            End If
        End Sub
    [C#]
              private void Button1_Click(object sender, System.EventArgs e)
              {
                  if( FormsAuthentication.Authenticate(username.Text, pwd.Value))
                  {
                      FormsAuthentication.RedirectFromLoginPage(username.Text, true);
                  }
                else
                      Response.Redirect("webform1.aspx");
              }

重新编译项目后启动,然后在输入用户名“小杨”及口令“5157”,如图1-20所示。

图1-20 测试改进后的应用

在图1-19所示的画面中单击【提交】按钮,将出现如图1-21所示的画面。

图1-21 小杨登录后的界面

还可以通过配置文件修改授权,例如下面的授权配置拒绝用户“晓华”和匿名用户登录:

        <authorization>
            <deny users="?,晓华"/>
                <allow users="*" />
        </authorization>

从本例可以看出,利用配置文件可以不用修改源代码而改变ASP.NET Web应用的行为。对开发人员而言,灵活地使用配置文件,也是一项重要的技能。

注意

在修改源代码后,请不要忘了先编译再执行!

1.3.9 第九步:部署

因为ASP.NET中所使用的组件都包含在程序集中,而程序集通过一个详细的清单实现了自描述,所以ASP.NET应用部署过程中不用考虑组件(例如传统的COM组件)的注册问题,可以通过复制策略把ASP.NET应用从开发服务器部署到最终的发行服务器上。集成开发环境提供了两种方法实现ASP.NET应用的部署:拷贝项目和使用安装项目。

假设我们要把开发服务器localhost上的ASP.NET应用CH1部署到发行服务器diana的CH1RELEASE虚目录下,则可以:

1.利用项目复制功能步骤

(1)选中要复制的ASP.NET项目。

(2)选择【项目】菜单,继续选择【复制项目】子菜单。

(3)这时将弹出“复制项目”对话框,如图1-22所示。设置好目标项目文件夹的名称和相关的复制选项,然后单击【确定】按钮。

图1-22 “复制项目”对话框

(4)这时会出现如图1-23所示的对话框指示复制进度。当项目复制完毕后,该对话框自动关闭。

图1-23 复制进度进度图

(5)复制结束后,通过浏览器访问发行服务器上的ASP.NET应用。

在浏览器的地址栏中发行服务器上的应用地址,如图1-24所示,将会出现开发服务器上类似的界面。

图1-24 访问部署到发行服务器上的ASP.NET应用

2.用Web安装项目部署步骤

(1)在解决方案资源视图下,右键单击解决方案,鼠标指向【新建项目】,然后在弹出的子菜单中单击【添加】按钮,如图1-25所示。

图1-25 往解决方案中添加项目

(2)这时会弹出“添加新项目”对话框,如图1-26所示。选择左边的“项目类型”列表框中的【安装和部署项目】,在右边的“模板”列表框中单击【Web安装项目】,在设置安装项目的名称和保存该项目的目录后,单击【确定】按钮。

图1-26 “添加新项目”对话框

(3)解决方案资源视图下的项目列表框中会出现新建的安装项目,右键单击该项目,鼠标引向【添加】后单击【项目输出】。

(4)这时会弹出如图1-27所示的“添加项目输出组”对话框。选择项目“CH1”,在列表框中选中“主输出”和“内容文件”,单击【确定】按钮,关闭对话框。

图1-27 “添加项目输出组”对话框

提示

对于CH1项目,只用发行编译后的程序集(项目主输出)和所有的*.aspx文件(内容文件)。至于代码隐藏文件(源文件)和资源和调试符号则不用部署到目标服务器上。

(5)右键单击安装项目,指向【视图】,单击【自定义操作】按钮。

(6)选中【自定义操作】节点,单击右键,单击【添加自定义操作】按钮。

(7)按照如图1-28所示进行选择,设置好后,单击【确定】按钮,关闭对话框。

图1-28 选择项目中的项

(8)右键单击安装项目,单击【生成】按钮,这时输出窗口将输入如图1-29所示的信息。

图1-29 编译安装项目时的输出窗口

(9)查看安装项目的调试(或发行)目录生成的安装文件,如图1-30所示。

图1-30 安装项目的生成文件

(10)把安装项目生成的安装文件复制到ASP.NET应用发行服务器Diana。

(11)在发行服务器Diana上运行安装文件。

启动安装后,会依次出现如图1-31至图1-35所示的画面。

图1-31 欢迎画面

图1-35 安装结束

图1-32 设置安装地址

图1-33 确认安装

图1-34 正在安装

(12)在浏览器上输入http://diana/WebSetupCH1/webform1.aspx,测试发行服务器上的ASP.NET应用。

提示

通过控制面板下的“添加/删除程序”工具删除安装的ASP.NET应用,如图1-36所示。

图1-36 通过“添加/删除程序”工具删除安装的ASP.NET应用

从整个安装实例来看,ASP.NET应用的部署是比较容易的。如果涉及到数据库访问,则部署ASP.NET应用时,还要考虑数据库的部署。

1.4 小结

本章简单介绍了直到ASP.NET诞生,Web应用开发的历史。本章的重点是通过开发一个基于窗体验证的登录Web窗体,介绍了ASP.NET应用开发的全貌。本章所涉及到的大量技术,在本书后面都有详细介绍。