官术网_书友最值得收藏!

第2章 第一個ASP.NET應用的單文件版本

第1章實現的第一個ASP.NET應用示例,展示了集成開發工具開發ASP.NET應用的全貌。讀者可能也體會到,無需對ASP.NET框架本身作深入了解,利用Visual Studio.NET就可以開發出很好的ASP.NET應用。雖然筆者鼓勵大家盡量用Visual Studio.NET開發ASP.NET應用,但在某些情況下,譬如手頭沒有集成開發工具或希望著手更多的事情以加深對ASP.NET的理解時,編寫單文件版本的ASP.NET應用可能是個好注意。單文件版本的ASP.NET應用中的代碼和界面混在同一個.aspx文件中,在第一次被請求時,它被動態編譯成程序集。這樣對于開發人員,就不用顯式地調用相應編程語言的編譯器編譯隱藏代碼文件了。

本章主要內容如下:

● Web窗體的基本語法

● 客戶端引發服務器端事件的底層實現

● 使用跟蹤排除錯誤

● 單文件版本的ASP.NET應用開發步驟

2.1 預備知識

為了順利編寫單文件版本的ASP.NET應用,讀者需要了解基本的窗體語法知識。

提示

這里僅提供有關窗體語法的一個基本介紹,進一步的介紹讀者可以參考本書第3章。

先看一個非常簡單的.aspx文件,該文件返回“Hello”給客戶:

    [Visual Basic]
    <%@ Page language="vb" %>
    <%-- 演示基于單文件的ASP.NET頁面 --%>
    <%
      Response.Write("<p>Hello")
    %>
    [C#]
    <%@ Page language="C#" %>
    <%-- 演示基于單文件的ASP.NET頁面 --%>
    <%
      Response.Write("<p>Hello");
    %>

第一行代碼是@ Page指令。利用@ Page指令的Language屬性設置頁面的編程語言。因為該指令在服務器端執行,所以被包圍在<%和%>之前。

第二行為服務器端的注釋語句。

第三行用<%聲明一段服務端代碼塊的開始。

第四行利用Response.Write方法向客戶端寫回“Hello”字符串。“<p>”表示一個段落標志。

第五行用%>聲明一段服務端代碼塊的結束。

對于Response.Write方法,存在一種簡化的方式,可以直接把其輸出放在“<%=”和“%>”直接,例如:

    [Visual Basic]
    <%@ Page language="vb" %>
    <% dim I as Integer
      For I=0 to 5
      %>
        <font size="<%=i%>"> <p>Hello World! </font>
    <% Next %>
    [C#]
    <%@ Page language="c#" %>
    <%
      for(int i=0;i<6;i++)
      {
      %>
        <font size="<%=i%>"> <p>Hello World! </font>
    <% } %>

執行結果如圖2-1所示。

圖2-1 執行結果

與Active Server Pages (ASP)不同,在ASP.NET的代碼塊(在<%和%>標志之間)中不能聲明函數或子例程。函數或子例程只能在<Script>和</Script>標志之間定義。例如下面的代碼演示了例程Hello的定義及其使用:

    [Visual Basic]
    <%@ Page language="vb" %>
    <Script runat="server">
      '定義例程
      sub sayHello()
        Response.Write("<p>Hello")
      end sub
    </Script>
    <%--
      調用例程
    --%>
    <% sayHello() %>
    [C#]
    <%@ Page language="c#" %>
    <Script runat="server">
      //定義例程
      void sayHello()
      {
        Response.Write("<p>Hello");
      }
    </Script>
    <%--
      調用例程
    --%>
    <% sayHello(); %>

上述頁面向客戶返回Hello。

上面的示例表明,在<Script></Script>代碼塊中使用注釋的方法跟在代碼隱藏文件中使用注釋的方法相同。一定要把Script的runat屬性設置為server,否則代碼將按默認設置在客戶端運行。

提示

請讀者一定要弄清楚代碼運行的位置,客戶端代碼的編程主要跟文檔對象模型,并且其語言為解釋型的腳本語言。而服務器端的代碼可以充分利用服務器端的各種資源,編程語言為編譯型的語言,并且可以動態發出客戶端代碼,例如:

                      [Visual Basic]
                      <%@ Page language="vb" %>
                      <Script runat="server">
                        '定義例程
                        sub sayHello()
                          Response.Write(" <Script language=JScript> ")
                          Response.Write("document.write('<p>Client Hello');")
                          Response.Write("</" & "Script>")
                          end sub
                      </Script>
                      <% sayHello() %>
                      [C#]
                      <%@ Page language="C#" %>
                      <Script runat="server">
                        //定義例程
                        void sayHello()
                        {
                          Response.Write(" <Script language=JScript> ");
                          Response.Write("document.write('<p>Client Hello');");
                          Response.Write("</" + "Script>");
                        }
                      </Script>
                      <% sayHello(); %>

在服務器端編寫的客戶端代碼可以直接放到客戶端腳本塊中。上面的代碼可以修改為:

    [Visual Basic]
    <%@ Page language="vb" %>
    <Script language=JScript>
      document.write('<p>Client Hello');
    </Script>
    [C#]
    <%@ Page language="c#" %>
    <Script language=JScript>
      document.write('<p>Client Hello');
    </Script>

修改后的代碼顯得更好讀一些。

提示

對于.aspx文件內的HTML標志,ASP.NET框架不會保持不變,只對特定的ASPX標志進行處理。

要想順利地設計出.aspx文件,還要掌握如何往Web窗體頁中添加Web服務器控件和HTTP控件。Web服務器控件在服務器端運行,它不直接對應到HTML元素,而是在請求時被動態呈現為合適的HTML元素。一個HTTM控件相當于一個HTML標志元素,例如HTML Button控件相當于Type屬性為“button”的INPUT HTML元素:

<INPUT type="button" >

還可以繼續指定該INPUT元素的其他屬性,例如Value、OnClick等,而這些屬性由客戶端的瀏覽器直接解釋:

<INPUT type="button" onclick="this.value='client clicked'" value="Button">

但是,ASP.NET框架為HTML標志增添了runat屬性,該屬性默認為“client”,可以通過將runat設置為server,把HTML控件轉變為服務器端的控件。這時允許在服務器端的腳本中添加跟該控件相關的代碼。例如下面的代碼在單擊HTML Button控件后,在服務器端激活OnServerClick事件:

    [Visual Basic]
    <%@ Page language="vb" %>
    <Script runat="server">
    sub Button1_ServerClick(sender as object,e as System.EventArgs)
      Button1.Value="Server Clicked"
    end sub
    </Script>
    <html>
    <title>演示HTML服務器端控件</title>
    <body>
      <form runat="server">
        <INPUT type="button"
                      OnServerClick="Button1_ServerClick"
                      value="Click Me!"
                      id="Button1"
                      runat="server">
      </form>
    </body>
    </html>
    [C#]
    <%@ Page language="cs" %>
    <Script runat="server">
    void Button1_ServerClick(object sender, System.EventArgs e)
    {
      Button1.Value="Server Clicked";
    }
    </Script>
    <html>
    <title>演示HTML服務器端控件</title>
    <body>
      <form runat="server">
        <INPUT type="button"
                      OnServerClick="Button1_ServerClick"
                      value="Click Me!"
                      id="Button1"
                      runat="server">
      </form>
    </body>
    </html>

從瀏覽器請求該網頁,將顯示標題為“Click Me!”的按鈕,單擊該按鈕后,按鈕的標題修改為“Server Cliicked”。

讀者可能對上述執行結果表示不解,客戶端引發的事件怎么就神不知鬼不覺地傳到了服務器端呢?服務器端又如何區分是哪個控件引發的事件呢?為了回答這個問題,我們看看該.aspx文件產生的回應HTML文件:

    <html>
    <title>演示HTML服務器端控件</title>
    <body>
      <form name="_ctl0" method="post" action="demo6.aspx" id="_ctl0">
    <input type="hidden" name="__EVENTTARGET" value="" />
    <input type="hidden" name="__EVENTARGUMENT" value="" />
    <input                   type="hidden"                   name="__VIEWSTATE"
value="dDwxOTI0MjI4NTEyO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8bDx2YWx1Z
Ts+O2w8U2VydmVyIENsaWNrZWQ7Pj47Oz47Pj47Pj47PlHYIMOTlQB7/IiD17MuoycLy603" />
    <Script language="javaScript">
    <!--
        function __doPostBack(eventTarget, eventArgument) {
            var theform = document._ctl0;
            theform.__EVENTTARGET.value = eventTarget;
            theform.__EVENTARGUMENT.value = eventArgument;
            theform.submit();
        }
    // -->
    </Script>
        <input   language="javaScript"   onclick="__doPostBack('Button1','')"   name="Button1"
id="Button1" type="button" value="Server Clicked" />
      </form>
    </body>
    </html>

提示

展開瀏覽器的【查看】菜單,單擊【源文件】將打開記事本顯示上述內容。

下面我將對產生的HTML文件做仔細說明,以幫助讀者弄明服務器如何處理客戶端引發的事件。

首先查看<form>元素,在.aspx文件中,通過下面的代碼添加了一個<form>元素(也就是一個HTML控件):

      <form runat="server">
      …
      </form>

因為指定在Server端運行,所以ASP.NET將對該標志進行翻譯,翻譯的結果包括:

● 設定Form元素的相關屬性,例如name、id、action等屬性。

● 添加3個隱藏域:一個隱藏域用以保存引發表單被發送的HTML控件,另一個隱藏域用以保存事件參數,還有一個用以保存跟服務器端控件狀態數據,這個隱藏域在服務端被稱為狀態視圖對象。前兩個隱藏域是服務器端能夠處理客戶端事件的關鍵之一。

.aspx文件中的HTML按鈕控件也是一個服務器端控件,所以ASP.NET框架也要負責把它翻譯成合適的HTML代碼,翻譯后的結果包括:

● 設置了name屬性。

● 設置了按鈕的客戶端腳本語言屬性(language屬性)。

● 重寫了OnClick屬性(該屬性是在客戶單擊按鈕后執行的代碼)。OnClick以按鈕的name屬性值為第一個參數調用客戶端的函數__doPostBack。__doPostBack根據傳入的兩個參數設置隱藏域__EVENTTARGET和隱藏域__EVENTARGUMENT的值,然后通過表單的submit方法向服務器回發網頁。

提示

上面的討論進一步說明了服務器端的HTML控件的特點,它們總是會在服務器端進行適當的處理后,才返回給客戶,而客戶端的HTML控件僅是一個HTML標志,ASP.NET框架不做任何處理而直接將其返回。

服務器接收到回發的請求后,通過檢查表單的隱藏域__EVENTTARGET獲得引發回發事件的HTML控件的name,從隱藏域__EVENTARGUMENT獲得跟事件處理相關的數據,接下來,ASP.NET根據name查找相應的對象,并以事件處理參數調用該對象相應的事件處理代碼。

從上面的討論可知,為了在服務器端處理服務器控件的事件,必須滿足如下要求:

● 該控件必須在服務器端運行。

● 該控件必須包含在一個服務器端運行的HTML Form控件內。

● 該控件的name屬性必須惟一的設置。

提示

可以指定服務器端控件的name屬性,但在ASP.NET呈現該控件時,總是會根據該控件的UniqueID屬性重新設置客戶端HTML元素的name屬性,以確保其惟一性。

我們將在本書的后續章節中對服務器端事件處理的深入討論。現在讀者只要知道可以編寫服務端控件(包括服務端的HTML控件和Web控件)的事件處理代碼,這些事件在客戶端引發,但在服務器上處理,ASP.NET框架通過兩個隱藏域傳遞跟引發事件的控件和相關事件參數。

對HTML控件,我們還想指出很重要的一點,那就是仍然可能指定客戶端的事件響應代碼。

    [Visual Basic]
    <%@ Page language="vb" %>
    <Script runat="server">
    sub Button1_ServerClick(sender as object,e as System.EventArgs)
      Button1.Value="Server Clicked"
    end sub
    </Script>
    <html>
    <title>演示HTML服務器端控件</title>
    <body>
      <form runat="server">
        <INPUT type="button"
              OnServerClick="Button1_ServerClick"
              onmouseover="this.style.backgroundColor='yellow'"
                  onmouseout="this.style.backgroundColor='lightgreen'"
                  style="font: 8pt verdana;
                      background-color:lightgreen;
                      border-color:black;
                      height:30;
                      width:200"
              id="Button1"
              runat="server">
      </form>
    </body>
    </html>
    [C#]
    <%@ Page language="cs" %>
    <Script runat="server">
    void Button1_ServerClick(object sender, System.EventArgs e)
    {
      Button1.Value="Server Clicked";
    }
    </Script>
    <html>
    <title>演示HTML服務器端控件</title>
    <body>
      <form runat="server">
        <INPUT type="button"
              OnServerClick="Button1_ServerClick"
              onmouseover="this.style.backgroundColor='yellow'"
                  onmouseout="this.style.backgroundColor='lightgreen'"
                  style="font: 8pt verdana;
                      background-color:lightgreen;
                      border-color:black;
                      height:30;
                      width:200"
              id="Button1"
              runat="server">
      </form>
    </body>
    </html>

提示

ASP.NET框架只支持有限個事件的服務器端的處理,例如單擊事件等。因為服務器端上的事件處理會涉及到一次客戶到服務器的一個往返行程,這樣對一些高頻的鼠標事件,例如onmouseover,放到客戶端處理更合適。

如果該控件單擊將引發表單回發,那么客戶端處理OnClick事件要小心,因為ASP.NET會自動把一段提交表單的客戶端腳本附加到OnClick中。在客戶端的OnClick看起來應為下面的形式:

    OnClick="客戶端代碼;"

這樣ASP.NET自動產生的客戶端腳本會自動附加到“客戶端代碼;”后不會產生錯誤。

注意

一定不要把“客戶端代碼;”中的“;”給遺漏了,否則將報告客戶端腳本有誤。

下面將介紹Web控件。跟HTML控件相比,Web控件只能是服務器端控件,因此必須把Web控件的runat屬性設置為server。另外,聲明Web控件時必須在類型前加上“asp:”命名空間,例如:

    <asp:Button id="Button3"  runat="server" Text="Web 按鈕控件" ToolTip="我是 Web 按鈕控件
"></asp:Button>

提示

命名空間用以保證命名的惟一,同時也是代碼的邏輯組織形式。

如果需要,還可以設置Web控件的更多屬性。

注意

Web控件的屬性跟HTML控件的屬性不同,它們用以標志服務器端Web控件自身的狀態,ASP.NET框架會根據自身的狀態繪產生合適的HTML代碼。例如上面的ASPX代碼將產生如下的HTML代碼:

      <input type="submit" name="Button3" value="Web按鈕控件" id="Button3" title="我是
      Web按鈕控件" />

從翻譯可以看出,Button Web按鈕控件被翻譯為一個類型為“submit”的HTML Input元素,控件的ToolTip屬性被翻譯為提交按鈕的Title屬性。

跟服務器端的HTML控件類似,也可以在服務器端處理Web控件的事件,而該事件是在客戶端引發的,例如:

    [Visual Basic]
    <%@ Page language="vb" %>
    <Script runat="server">
      shared  clickcount  as  Integer=0
          Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
            clickcount+=1
            Response.Write(clickcount)
        End Sub
    </Script>
    <html>
    <title>演示Web控件</title>
    <body>
      <form runat="server">
          <asp:Button id="Button1"
              OnClick="Button1_Click"
            runat="server"
              Text="Web按鈕控件"
              ToolTip="我是Web按鈕控件"/>
      </form>
    </body>
    </html>
    [C#]
    <%@ Page language="cs" %>
    <Script runat="server">
      static int clickcount =0;
      private void Button1_Click(object sender, System.EventArgs e)
      {
        clickcount++;
        Response.Write(clickcount);
      }
    </Script>
    <html>
    <title>演示Web控件</title>
    <body>
      <form runat="server">
          <asp:Button id="Button1"
              OnClick="Button1_Click"
            runat="server"
              Text="Web按鈕控件"
              ToolTip="我是Web按鈕控件"/>
      </form>
    </body>
    </html>

上述代碼的執行結果如圖2-2所示。這時單擊窗體上的按鈕,數字將不斷增大。

圖2-2 執行結果

說明

(1)示例代碼中的第三行聲明一個靜態變量(也就是為.aspx頁面對應的Web窗體類添加了一個靜態成員)。注意,不能在<%…%>之間聲明靜態成員,只能在服務端的腳本塊中聲明。

(2)通過把事件處理的方法直接賦值給Web控件的“On事件”屬性,可以在服務器端處理服務控件的事件。

除此之外,下面的代碼也能正確地處理鼠標的單擊事件:

    [Visual Basic]
    <%@ Page language="vb" %>
    <Script runat="server">
      shared  clickcount  as  Integer=0
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
          clickcount+=1
          Response.Write(clickcount)
      End Sub
      Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs)
        AddHandler Button1.Click ,addressof me.Button1_Click
      End Sub
    </Script>
    <html>
    <title>演示Web控件</title>
    <body>
      <form runat="server">
        <asp:Button id="Button1"
          runat="server"
              Text="Web按鈕控件"
              ToolTip="我是Web按鈕控件"/>
      </form>
    </body>
    </html>

說明

Visual Basic.NET中用Addhandler方法將特定的處理方法和控件的事件關聯。關聯的實質是實例化一個委托并將之賦值給控件的某個事件(不要忘了,在.NET中,事件就是一個委托變量!)

    [C#]
    <%@ Page language="cs" %>
    <Script runat="server">
      static int clickcount=0  ;
      private void Button1_Click(object sender, System.EventArgs e)
      {
        clickcount++;
          Response.Write(clickcount);
      }
      private void Page_Init(Object sender , System.EventArgs e)
      {
        Button1.Click+=new System.EventHandler(Button1_Click);
      }
    </Script>
    <html>
    <title>演示Web控件</title>
    <body>
        <form runat="server">
        <asp:Button id="Button1"
          runat="server"
          Text="Web按鈕控件"
          ToolTip="我是Web按鈕控件"/>
        </form>
    </body>
    </html>

說明

C#用“+=”把控件事件和處理代碼掛鉤。請注意,默認情況下Web窗體的AutoEventWireup屬性為True,這時,頁面的Init事件發生時,會自動調用Page_Init方法。如果指定頁面的AutoEventWireup的屬性為False,那么必須如下修改代碼:

                      [Visual Basic]
                      <%@ Page language="vb" AutoEventWireup="false"%>
                      …
                      Private  Sub  Page_Init(ByVal  sender  As  System.Object,  ByVal  e  As
                  System.EventArgs) Handles MyBase.Init
                          AddHandler Button1.Click ,addressof me.Button1_Click
                      End Sub
                      評注:Visual Basic.NET允許用Handlers關鍵字將處理代碼和事件直接掛鉤。
                      [C#]
                      <%@ Page language="cs" AutoEventWireup="false"%>
                      …
                      override protected void OnInit(EventArgs e)
                      {
                            Button1.Click+=new System.EventHandler(Button1_Click);
                      }

說明

當Web頁面被創建時,Web窗體的Init事件被引發。引發后實際上是調用OnInit方法,OnInit方法又會通過代理調用具體的事件處理代碼。

2.2 排除錯誤

因為缺少智能代碼提示,編寫單文件的ASP.NET應用時發生錯誤更是難免。不過ASP.NET框架本身為排除.aspx文件中的編碼錯誤提供了很好的支持。動態編譯.aspx文件時發生編譯錯誤,都會返回給調用者,并給出排除錯誤的建議。

請建立具有下面內容的.aspx文件:

            [Visual Basic]
            <%@Page language="vb"AutoEventWireup="true"%>
            <Script runat="server">
              Private Sub Page_Load(ByVal sender As System.Object,ByVal e As System.EventArgs)
                if not IsPostBack then
              Label1.Text=System.Now.ToString("f")
                end if
              End Sub
            </Script>
            <html>
            <title>演示排除錯誤</title>
            <body>
            <form runat="server">
                <asp:Label id="Label1" runat=server/>
            </form>
            </body>
            </html>
            [C#]
    <%@ Page language="cs" AutoEventWireup="true"%>
    <Script runat="server">
      private void Page_Load(object sender, System.EventArgs e)
      {
        // 在此處放置用戶代碼以初始化頁面
        if(! IsPostBack)
        {
            Label1.Text=System.Now.ToString("f");
        }
      }
    </Script>
    <html>
    <title>演示排除錯誤</title>
    <body>
        <form runat="server">
            <asp:Label id="Label1" runat=server/>
        </form>
    </body>
    </html>

上述代碼的本意是在標簽上顯示服務器上的當前時間。但是Now應是System.DateTime對象的屬性,而不是System的屬性,這樣當在瀏覽器上請求該窗體時,將獲得編譯錯誤信息,如圖2-3所示。

圖2-3 編譯錯誤提示信息

提示

在圖2-3中單擊【顯示詳細的編譯器輸出】按鈕,可以了解.aspx文件被動態編譯的細節,譬如引用了哪些程序集,動態生成的程序集保存的位置等。在圖2-3中單擊【顯示完整的編譯源】按鈕,還可以查看ASP.NET根據.aspx文件動態產生的源代碼文件,如圖2-4所示。

圖2-4 根據.aspx文件動態產生的源代碼

從圖2-4可以清楚地看出,.aspx文件被轉化為一個System.Web.UI.Page派生類。

圖2-4中的錯誤提示信息指出了發生錯誤的源代碼所在的位置,給出了解決該錯誤的建議方法,這樣排除錯誤就很容易了。用System.DateTime.Now替換“System.Now”,就修正了錯誤,然后刷新請求,將會出現如圖2-5所示的正確結果。

圖2-5 排除錯誤后獲得正確結果

提示

單文件窗體的一個好處是修改.aspx文件后,不用編譯,再次請求該頁,就能看到更新的結果。

排除錯誤的另外一個可用的強大工具就是ASP.NET跟蹤,通過將@Page指令的Trace屬性設置為true就可以啟用跟蹤:

    [Visual Basic]
    <%@ Page language="vb" AutoEventWireup="true" Trace="true"%>
    [C#]
    <%@ Page language="cs" AutoEventWireup="true" Trace="true"%>

啟用跟蹤后,ASP.NET在響應每個請求時,會詳細列出下面的信息:

● 請求詳細信息

包括會話ID、請求類型、請求的時間、狀態代碼、請求編碼和響應編碼,某次請求的詳細信息如圖2-6所示。

圖2-6 請求詳細信息

● 跟蹤信息

所有Trace.Write方法輸出的信息都在這兒列出,ASP.NET框架預先在Page_Init等方法中加入了Trace.Write調用輸出以輸出跟蹤信息,如圖2-7所示。

圖2-7 跟蹤信息

● 控件樹

詳細列出了Web窗體頁面上的各種控件及父子關系,如圖2-8所示。

圖2-8 控件樹

● 標頭集合

列出了服務器返回給客戶的Header(標頭)信息,如圖2-9所示。

圖2-9 標頭集合

● 服務器變量

列出服務器端的所有變量,如圖2-10所示。

圖2-10 服務器變量

上述信息能幫助開發人員全面地了解在一次Web窗體請求過程中所發生的事情的所有細節,當然也是排除錯誤的絕佳輔助工具。

另外,通過調用Trace對象的Write方法,還能將自定義的消息寫到跟蹤消息欄中,例如把下面的代碼插入到.aspx文件的Page_Load方法中。

    [Visual Basic]
    <%@ Page language="vb" Trace="true"%>
    <Script runat="server">
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
            Trace.Write("頁面事件", "調試-Page_Load")
        End Sub
    </Script>
    <html>
      <title>演示Trace.Write</title>
    </html>
    [C#]
    <%@ Page language="cs" Trace="true"%>
    <Script runat="server">
      private void Page_Load(object sender, System.EventArgs e)
      {
        Trace.Write("頁面事件", "調試-Page_Load");
      }
    </Script>
    <html>
      <title>演示Trace.Write</title>
    </html>

在瀏覽器中請求上述內容的.aspx文件,執行結果如圖2-11所示。黑體字突出顯示的代碼的輸出在圖2-11中用方框圈住。

圖2-11 執行結果

如果錯誤排除了,需要取消跟蹤,那么將@Page指令的Trace屬性設置為false即可。

提示

在集成開發環境下,調試一個ASP.NET應用跟調試其他.NET應用沒什么不同,在隱藏代碼文件中設置斷點,然后按【F5】鍵啟動調試。但如果要調試但文件版本中的腳本,可以用.NET框架提供的CLR調試器DbgClr.exe,該調試器位于.NET框架安裝的GuiDebug目錄下。本書后面將詳細介紹用DbgClr.exe調試.aspx頁面的技術。

2.3 實現步驟

有了前面的準備知識,下面我們將實現第一個ASP.NET應用的單文件版本的實現步驟。

2.3.1 第一步:建立Web應用目錄

在d:盤上新建一個demoasp目錄,然后到【控制面板】上雙擊【管理工具】,雙擊【Internet信息服務】圖標,激活IIS管理工具。

右鍵單擊【默認Web站點】按鈕,指向【新建】,在彈出的子菜單中單擊【虛擬目錄】按鈕,如圖2-12所示,將激活新建虛擬目錄向導。

圖2-12 利用關聯菜單新建虛擬目錄

按照向導提示,依次設置虛擬目錄的別名(如圖2-13所示)、對應的磁盤目錄(如圖2-14所示,本例中設置為d:\demoasp)和虛擬目錄的訪問權限(如圖2-15所示)。

圖2-13 設置虛擬目錄別名

圖2-14 設置虛擬目錄對應的磁盤目錄

圖2-15 設置虛擬目錄的訪問權限

提示

一個Web應用對應著一個IIS虛擬目錄,虛擬目錄的別名可以跟對應的磁盤目錄名不一致。客戶通過虛擬目錄別名訪問Web應用。假設服務器diana上有別名為demoASP的虛擬目錄對應到磁盤目錄d:\demo,而磁盤目錄demo下有文件default.aspx,那么為了訪問該文件,可以在瀏覽器請求地址欄中的URL為http://diana/demoASP/default.aspx

2.3.2 第二步:創建登錄的.aspx文件

文件版本的登錄窗體文件為login.aspx,位于d:\demoasp目錄下,其內容如下:

    [Visual Basic]
    <%@ Page Language="vb" %>
    <Script runat=server>
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
          If FormsAuthentication.Authenticate(username.Text, pwd.Value) Then
              FormsAuthentication.RedirectFromLoginPage(username.Text, True)
          Else
                Response.Redirect("login.aspx")
            End If
        End Sub
    </Script>
    <HTML>
        <HEAD>
            <title>請輸入用戶名和口令WebForm1</title>
        </HEAD>
        <body >
            <form  runat="server">
                <table border=0 align=center width=400>
                    <tr>
                      <td width=150>
                    <asp:label id="Label1"  runat="server">用戶名</asp:label>
                      </td>
                    <td width=200>
                  <asp:TextBox id="username" runat="server"></asp:TextBox>
                    </td>
                    <td width=50>
                      <asp:RequiredFieldValidator  id="RequiredFieldValidator1"    runat=
"server" ErrorMessage="用戶名不能為空" ControlToValidate="username" Display="Dynamic">*
</asp:RequiredFieldValidator>
                    </td>
                  </tr>
                  <tr>
                    <td>
                      <asp:label id="Label2"  runat="server">口令</asp:label>
                    </td>
                    <td>
                  <INPUT id="pwd"  type="password"name="Password1"runat="server">
                    </td>
                    <td>
                      <asp:RequiredFieldValidator           id="RequiredFieldValidator2"
runat="server" ErrorMessage="用戶名不能為空" ControlToValidate="pwd" Display="Dynamic">
*</asp:RequiredFieldValidator>
                    </td>
                  </tr>
                    <tr>
                      <td></td>
                      <td align=center>
                    <asp:Button   id="Button1"     runat="server"   Text="  提  交  "
OnClick="Button1_Click"></asp:Button>
                  </td>
                  <td></td>
                    </tr>
                    <tr>
                      <td></td>
                        <td width=400>
                          <asp:ValidationSummary  id="ValidationSummary1"   runat="serv
    ></asp:ValidationSummary>
                        </td>
                      <td?</td>
                    </tr>
                </table>
            </form>
        </body>
    </HTML>
    [C#]
    <%@ Page Language="cs" %>
    <Script runat=server>
            private void Button1_Click(object sender, System.EventArgs e)
            {
                if( FormsAuthentication.Authenticate(username.Text, pwd.Value))
                {
                    FormsAuthentication.RedirectFromLoginPage(username.Text, true);
                }
                            else
                    Response.Redirect("login.aspx");
                }
    </Script>

其他代碼跟編程語言為Visual Basic時相同,省略…

提示

利用<table></table>元素幫助對其控件。<tr></tr>表示定義一行,<td></td>表示定義一列。

繼續創建默認的窗體default.aspx,其實現代碼如下所示:

    [Visual Basic]
    <%@ Page Language="vb" %>
    <Script runat=server>
          Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
          If Not IsPostBack Then
                      Label1.Text=User.Identity.Name&",歡迎光臨"
          End If
          End Sub
          Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
          FormsAuthentication.SignOut()
          End Sub
    </Script>
    <HTML>
                <HEAD>
                    <title>請輸入用戶名和口令WebForm1</title>
                </HEAD>
                <body >
                    <form  runat="server">
                      <table border=0 align=center width=400>
                        <td width=300>
                            <asp:Label id="Label1" runat="server" >歡迎光臨</asp:Label>
                        </td>
                        <td>
                           <asp:Button    id="Button1"    runat="server"       Text="Sign    Out"
        OnClick="Button1_Click"></asp:Button>
                        </td>
                      </table>
                    </form>
                </body>
    </HTML>
    [C#]
    <%@ Page Language="cs" %>
    <Script runat=server>
                    private void Page_Load(object sender, System.EventArgs e)
                    {
                        if(!IsPostBack)
                        Label1.Text = User.Identity.Name + ",歡迎光臨";
                    }
                        private void Button1_Click(object sender, System.EventArgs e)
                    {
                        FormsAuthentication.SignOut();
                    }
    </Script>

下面的代碼跟語言為Visual Basic時相同。

2.3.3 第三步:編寫配置文件

在demoasp目錄下新建一個web.config文件,其內容如下:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.web>
          <authentication mode="Forms">
            <forms loginURL="login.aspx">
              <credentials passwordFormat = "Clear" >
                  <user name="小楊" password="5157"/>
                  <user name="曉華" password="1234"/>
              </credentials>
                  </forms>
                  </authentication>
                  <authorization>
          <deny users="?,曉華"/>
          <allow users="*" />
                  </authorization>
      </system.web>
    </configuration>

配置文件中的第一行XML序言不可省略,否則將報告配置文件中無效的字符,如圖2-16所示。

圖2-16 配置錯誤

2.3.4 第四步:測試

直接在瀏覽器下輸入http://diana/demoasp/default.aspx會自動導入到登錄畫面。在登錄畫面中的用戶名中輸入“小楊”,口令中輸入“5157”,再單擊【提交】按鈕則會成功導入default.aspx畫面。如果登錄畫面輸入了其他用戶,則不需離開登錄畫面而直接進入default.aspx畫面。

2.3.5 第五步:部署

把login.aspx、default.aspx和web.config文件拷貝到目標服務器某個虛擬目錄對應的磁盤目錄下,就完成了在發行服務器上的部署。這個過程中沒有涉及到任何程序集。

提示

如果.aspx窗體用到了自動編譯過程中沒有自動添加對其引用的程序集,則應該把這些程序集也復制到目標服務器Web應用的bin子目錄下。

2.3.6 第六步:開發單文件版本的ASP.NET應用

如果已有Visual Studio.NET工具,則可以用它來簡化單文件窗體的設計。按照下面介紹的方法,可以把一個具有隱藏代碼文件的窗體輕松地轉化為一個單文件窗體。

● 新建一個Web窗體,新建的窗體為Webform3。

● 利用Web窗體設計器設計窗體,設計好的Web窗體如圖2-17所示。

圖2-17 設計好的Web窗體

設計好的界面最上邊是一個廣告控件AdRotatorl,下面是一個HTML表格Table控件。表格的第一行依次為HTML標簽控件、Web文本框控件和Web必須域驗證控件,它驗證的控件是文本框;表格的第二行中間是Web按鈕控件;表格第三行是Web驗證匯總控件。

● 編寫代碼

一般可以為界面元素添加事件處理的代碼,譬如添加“Go!”按鈕的單擊事件的響應,或添加一些公共的方法:

    [Visual Basic]
        Sub PageSub(ByVal para As Object)
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Handles Button1.Click
          '添加處理事件單擊的代碼
        End Sub
    [C#]
          void PageSub(object para)
          {
          }
        private void Button1_Click(object sender, System.EventArgs e)
          {
          }

提示

除此之外,隱藏代碼文件還有Web窗體設計器自動產生的代碼,以及在新建一個Web窗體時自動產生的代碼。

● 實施轉化

修改.aspx文件的第一行,修改后的代碼看起來應如下所示:

    [Visual Basic]
    <%@ Page language="vb" AutoEventWireup="false" %>
    [C#]
    <%@ Page language="c#" AutoEventWireup="false" %>

然后在.aspx文件的第三行新加如下的代碼塊:

    <Script runat=server>
    </Script>

接下來,把隱藏代碼文件中的實現Web頁類的代碼拷貝到<Script></Script>代碼塊內,注意,那些跟界面元素相關的變量聲明,以及類本身的聲明不用拷貝。若編程語言為Visual Basic,則要對拷貝后的代碼做進一步的處理,即修改跟處理界面元素事件相關的代碼:

(1)去掉事件處理代碼方法聲明中的Handers關鍵字及其以后的代碼,例如,把:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles
Button1.Click

修改為:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

(2)在Page_Init方法的最后,手工將事件處理代碼和界面控件的事件掛鉤,例如在Page_Init的最后添加下面的代碼:

    AddHandler Button1.Click, AddressOf Button1_Click

根據隱藏代碼合成的單文件Web窗體文件最后看起來如下所示:

    [Visual Basic]
    <%@ Page Language="vb" AutoEventWireup="false" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <!--下面的代碼直接從隱藏代碼中拷貝而來 -->
    <Script runat="server">
      #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()
          '添加的代碼,手工掛鉤事件
          AddHandler Button1.Click, AddressOf Button1_Click
        End Sub
    #End Region
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Handles MyBase.Load
          '在此處放置初始化頁的用戶代碼
        End Sub
        Sub PageSub(ByVal para As Object)
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
          '添加處理事件單擊的代碼
        End Sub
    </Script>
    <HTML>
                <HEAD>
                        <title>WebForm3</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">
                        <FONT face="宋體">
                        <TABLE id="Table2" style="Z-INDEX: 101; LEFT: 50px; WIDTH: 300px;
        POSITION: absolute; TOP: 94px; HEIGHT: 86px" cellSpacing="1" cellPadding="1" width="300"
        border="0">
                            <TR>
                                        <TD style="WIDTH:152px;HEIGHT:30px">
                                        <DIV style="DISPLAY: inline; WIDTH: 146px; HEIGHT:
        31px"ms_positioning="FlowLayout">輸入查詢條件</DIV>
                                        </TD>
                                        <TD style="HEIGHT:30px">
                                        <asp:TextBox                                  id="TextBox1"
        runat="server"></asp:TextBox></TD>
                                        <TD style="HEIGHT:30px">
                                        <asp:RequiredFieldValidator id="RequiredFieldValidator1"
        runat="server"  ErrorMessage=" 查 詢 條 件 不 能 為 空 "  ControlToValidate="TextBox1">*
        </asp:RequiredFieldValidator></TD>
                            </TR>
                            <TR>
                                        <TD style="WIDTH:152px"></TD>
                                        <TD>
                                        <asp:Button  id="Button1"         runat="server"  Text="Go!"
        Width="121px"></asp:Button></TD>
                                        <TD></TD>
                            </TR>
                            <TR>
                                        <TD style="WIDTH:152px"></TD>
                                        <TD>
                                        <asp:ValidationSummary      id="ValidationSummary1"
        runat="server"></asp:ValidationSummary></TD>
                                        <TD></TD>
                            </TR>
                        </TABLE>
                        <asp:AdRotator  id="AdRotator1"  style="Z-INDEX:          102;  LEFT:  32px;
        POSITION:    absolute;   TOP:   11px"   runat="server"        Width="425px"   Height="60px"
        AdvertisementFile="XMLFile1.xml"BackColor="CornflowerBlue"></asp:AdRotator>
                        </FONT>
                        </form>
                </body>
    </HTML>
    [C#]
    <%@ Page language="c#" AutoEventWireup="false" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
    <!--下面的代碼直接從隱藏代碼中拷貝而來 -->
    <Script runat=server >
                        private void Page_Load(object sender,System.EventArgs e)
                        {
                        // 在此處放置用戶代碼以初始化頁面
                        }
                        #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.Button1.Click+=new System.EventHandler(this.Button1_Click);
                        this.Load+=new System.EventHandler(this.Page_Load);
                        }
                        #endregion
                        void PageSub(object para)
                        {
                        }
                private void Button1_Click(object sender,System.EventArgs e)
                        {
                        }
    </Script>
    <HTML>
                <HEAD>
                        <title>WebForm3</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">
                        <FONT face="宋體">
                        <asp:AdRotator  id="AdRotator1"  style="Z-INDEX:          102;  LEFT:  41px;
        POSITION: absolute; TOP: 11px" runat="server" Width="425px" AdvertisementFile="XMLFile1.xml"
        Height="60px"BackColor="CornflowerBlue"></asp:AdRotator>
                        <TABLE id="Table2" style="Z-INDEX: 103; LEFT: 53px; WIDTH: 300px;
        POSITION: absolute; TOP: 108px; HEIGHT: 86px" cellSpacing="1" cellPadding="1" width="300"
        border="0">
                            <TR>
                                        <TD style="WIDTH:152px;HEIGHT:30px">
                                        <DIV style="DISPLAY: inline; WIDTH: 146px; HEIGHT:
        31px"ms_positioning="FlowLayout">輸入查詢條件</DIV>
                                        </TD>
                                        <TD style="HEIGHT:30px">
                                        <asp:TextBox                                  id="TextBox1"
        runat="server"></asp:TextBox></TD>
                                        <TD style="HEIGHT:30px">
                                        <asp:RequiredFieldValidator id="RequiredFieldValidator2"
        runat="server"  ControlToValidate="TextBox1"  ErrorMessage="  查  詢  條  件  不  能   為  空
        ">*</asp:RequiredFieldValidator></TD>
                            </TR>
                            <TR>
                                        <TD style="WIDTH:152px"></TD>
                                        <TD>
                                        <asp:Button id="Button1" runat="server" Width="121px"
        Text="Go!"></asp:Button></TD>
                              <TD></TD>
                          </TR>
                          <TR>
                              <TD style="WIDTH:152px"></TD>
                              <TD>
                                  <asp:ValidationSummary      id="ValidationSummary1"
runat="server"></asp:ValidationSummary></TD>
                              <TD></TD>
                          </TR>
                        </TABLE>
                    </FONT>
                </FORM>
        </body>
    </HTML>

好了,借助于Visual Studio.NET,不需要對ASP.NET語法有多少了解,我們就有了設計任意復雜的單文件窗體的能力。當然,為了更好地設計Web窗體,對ASP.NET語法的深入了解是必要的,本書后續章節將在本章的基礎上,進一步介紹ASP.NET語法。

2.4 小結

本章介紹了開發單文件版本的ASP.NET應用的全貌。開發單文件版本的ASP.NET應用需要更多地了解ASP.NET的語法,并可能會產生更多的錯誤。本章提供了ASP.NET語法的綜述性的介紹,并提供了排除ASP.NET應用中BUG的方法。本章的重點仍然是第一個ASP.NET應用的單文件版本的實現步驟。本章最后還介紹了如何利用Visual Studio.NET來開發單文件版本的ASP.NET應用。

主站蜘蛛池模板: 通州市| 墨江| 临沧市| 自治县| 克山县| 东阳市| 新郑市| 罗平县| 蓬安县| 专栏| 浦城县| 宜昌市| 丰台区| 雅安市| 镇宁| 梨树县| 钦州市| 宜都市| 射阳县| 崇文区| 堆龙德庆县| 观塘区| 墨脱县| 西林县| 裕民县| 台山市| 定襄县| 库车县| 许昌县| 隆化县| 崇阳县| 集贤县| 阳新县| 松原市| 喜德县| 依安县| 舞阳县| 和硕县| 仁怀市| 财经| 柏乡县|