2011年2月17日 星期四

3-1 如果你過去是ASP開發人員

        我們的第一個案例,就來看看過去在ASP時代中稍具難度的使用者登入介面,說它稍具難度,是因為如果初次接觸ASP的程式設計師,絕對無法立刻撰寫出登入介面,但是對於稍稍熟悉ASP的程式設計師,登入介面可能就是家常便飯了。
        登入介面這類的程式都會涉及到兩三個網頁之間的相互呼叫、表單<FORM>傳值與接值,以及Session變數的運作。因此,從這個實例,您可以很輕易的發現ASPASP.NET之間的不同處...

3-1-1 過去ASP時代的做法

 

        登入介面的設計可能因人而異,但是一般來說,ASP登入介面的基本流程,會以底下這樣的方式來進行:




        此例是把A網頁和B網頁合併的例子,因此注意程式中第116行,就是我們在上圖中所謂的B網頁,後面17行到43行則是A網頁的部分(但記得此例中我們合併成一個網頁login.asp)

        網頁第一次執行的時候,由於Account=Request.form("UserAccount")Password=Request.form("Password")都不會取得資料,因此後面的帳號密碼判斷式當然都不會成立,因此繼續執行,直到出現底下的網頁(透過17行到43)


        注意第22行的<form method="POST" action="login.asp">敘述,當使用者輸入密碼之後,由於action位置為login.asp,所以按下[提交]鈕之後,網頁會SubmitLogin.asp自己,同時將表單<FORM>裡面的內容傳遞給Login.asp自己,這次執行網頁時,Account=Request.form("UserAccount")就會接收到使用者輸入的帳號和密碼等資料,因此:

Account=”Milk_Lin” Password=”good”

        後面的判斷式就會成立,session("isLogin")被設為true,然後轉址(Response.redirect)Process.asp,登入介面就這樣完成了。

至於Process.asp,我們則會加上下面這一段程式(2)
process.asp
0001:<%
0002:if session("isLogin")<>true then response.redirect("login.asp")
0003:%>
0004:<html>
0005:<head>
0006:<title>被保護的網頁</title>
0007:</head>
0008:<body>
0009:<p>被保護的網頁</p>
0010:</body>
0011:</html>

        2行中的if session("isLogin")<>true then response.redirect("login.asp")是防止不法使用者在還沒透過Login.asp登入的狀況下,直接輸入網址process.asp闖關的措施。如果session("isLogin")不為true,則表示該使用者還沒合法的透過Login.asp登入過,因此直接轉向到login.asp

        好了,這是過去ASP的做法,而ASP.NET呢?有何不同?

3-1-2  ASP.NET的做法

        我們看一個效果完全一樣的ASP.NET網頁,我們先使用Visual Studio.NET,新增一個Web專案:


        接著我們在專案中新增一個Web Form網頁,命名為login.aspx


        我們利用Visual Basic.NET工具箱,拖曳兩個Form控制項TextBox 和一個Web控制項Button,放置到Web Form網頁上:

        曳到Web Form上面後,您可以在控制項上按下滑鼠右鍵,出現選單後按下『屬性』,將會出現屬性視窗,可設定該Web控制項的名稱:
        請分別將該按鈕名稱設為Button_Submit,另外兩個TextBox設為txtAccounttxtPassword

        完成後應如下圖所示:

您可以先在上圖的編輯畫面中,切換到HTML碼部分:
0001:<%@ Page Language="vb" AutoEventWireup="false" Codebehind="login.aspx.vb" Inherits="AspxDemo.login"%>
0002:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
0003:<HTML>
0004:    <HEAD>
0005:               <title>login</title>
0006:               <meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.0">
0007:               <meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
0008:               <meta name="vs_defaultClientScript" content="JavaScript">
0009:               <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
0010:    </HEAD>
0011:    <body>
0012:               <form id="Form1" method="post" runat="server">
0013:                          <P><FONT face="新細明體">帳號:
0014:                                               <asp:TextBox id="txtAccount" runat="server" DESIGNTIMEDRAGDROP="14"></asp:TextBox></FONT></P>
0015:                          <P><FONT face="新細明體">密碼:
0016:                                               <asp:TextBox id="txtPassword" runat="server" TextMode="Password"></asp:TextBox>
0017:                                               <asp:Button id="Button_Submit" runat="server" Text="提交"></asp:Button></FONT></P>
0018:               </form>
0019:    </body>
0020:</HTML>


        扣除<HEAD>之外,真正核心的HTML在第11行到19行的部分,您可以對比前面我們該才介紹過的ASP網頁,兩者有著幾個地方相當不同:
n   12<FORM>的部分加上了runat="server",變成<form id="Form1" method="post" runat="server">
n   14行和第16行的<asp:TextBox …></asp:TextBox >是我們不曾看過的指令,該指令用來表示.NET Web Form上面的TextBox控制項
n   17行的<asp:Button>也是我們不曾看過的,用來表示Button控制項
n   1行多了:<%@ Page Language="vb" AutoEventWireup="false" Codebehind="login.aspx.vb" Inherits="AspxDemo.login"%>

        上面這幾個不同之處,我們後面介紹Web Form時會仔細的說明,我們先切回Visual Basic.NET中的『設計』畫面,然後在按鈕上Double-ClickVisual Basic.NET會切換到程式設計畫面:

請在Button_Submit_Click中鍵入下列6-12行的程式:
0001:    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
0002:        '在此加入要初始化頁面的使用者程式碼
0003:    End Sub
0004:
0005:    Private Sub Button_Submit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Submit.Click
0006:        If Me.txtAccount.Text = "Milk_Lin" And Me.txtPassword.Text = "good" Then
0007:            '設定 session 表示使用者已經 login
0008:            Session("isLogin") = True
0009:
0010:            '轉到實際被保護的網頁
0011:            Response.Redirect("Process.aspx")
0012:        End If
0013:    End Sub


        這段程式幾乎和我們在ASP中設計的一模一樣,唯一最大的不同是什麼?沒錯,少了原本在login.asp的第5,6行,表單的Request.Form(“xxx”)接值動作。取而代之的是『Me.txtAccount.Text』和『Me.txtPassword.Text』。

        撰寫ASP.NET的程式時,Web Form設計概念上相當接近VBEvent-Driven觀念,當使用者按下了網頁上的Button之後,會觸發Button_Submit_Click事件,進而執行上面第612行程式。

        Web Form網頁,在VB.NET程式碼中可用『me』表示,而網頁上的Web控制項,則可表示成『Me.txtAccount』。使用者輸入的值,則可透過『Me.txtAccount.Text』來取得。因此透過第6行的判斷式,我們即可判斷使用者輸入的帳號密碼,若正確,一樣設定Session("isLogin")的值,並且轉址到Process.aspx

        我們用同樣的方式來新增Process.aspx網頁,然後在空白頁面上Double-Click,則會直接出現程式設計畫面:

我們輸入底下程式:
0001:    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
0002:        '在此加入要初始化頁面的使用者程式碼
0003:        If Session("isLogin") <> True Then Response.Redirect("login.aspx")
0004:    End Sub


        3行的程式和我們之前設計的ASP網頁一模一樣,有趣的是,剛才當我們在網域上直接Double-Click頁面的時候,程式設計畫面也會直接跳到『Page_Load』事件的程式碼中(和在VB裡面設計程式一模一樣)

        Page_Load裡面撰寫的程式代表著當網頁被載入的時候要執行的動作。當我們輸入好上面的程式後,接著我們直接按下選單上的『建置→建置方案』,然後輸入網址Process.aspx來執行該網頁。

執行結果如下,和我們之前的ASP網頁一模一樣:
        回憶一下剛才的整個動作,您會發現ASPASP.NET在設計理念上相當不同,除了之前我們看到的<asp:TextBox>runat="server"等怪怪的指令之外,ASP.NET的核心物件 Web Form,則是整個.NETWeb應用程式設計上的重點。

Web Form有下列幾個特性:
n   一個Web Form即表示一張網頁,副檔名為.aspx,地位同等於過去的.asp
n   Web Form本身即是一個物件,類似VB程式設計中的表單物件Form
n   每個Web Form上面都可以佈置一些Web控制項,這點也類似VB
n   Web FormWeb控制項,都擁有自己的事件、屬性、方法
n   Web Form和程式碼可以分開(Code Behind)

        因此,從ASPASP.NET,在設計方式上有著不少的差異,整個流程變成下圖的方式,其中架構上完全一致,但最大的不同則是,對於程式設計師來說,ASP.NET『似乎』少了Submit這個動作(注意,我們說『似乎』是因為實際上這個動作依然存在,只是被Web Form包裝起來在背景完成了)
        過去我們在程式中會在接收Submit動作的網頁上,撰寫Request.form(“物件ID”),來取得從上個網頁裡面的<FORM>表單中傳來的物件值,然後進行處理,而這個動作在ASP.NET中則被Web Form取代了(或說封裝起來)。我們在程式中,可以不需要理會複雜的表單傳值與接值的動作,而直接對資料進行操作。

        這樣有什麼好處?對程式設計師來說,這樣可以專注在處理資料,而非傳值與接值這類的『虛工』上。在過去,ASP網頁上的傳接值這類工作,是由於網際網路的特性而產生,在程式設計上並非必要(並非必要的意思是,不會因為這樣的動作而產生任何的『效益或價值』,只是花時間),特別是倘若表單上的欄位相當多的時候(不像此例只有帳號和密碼),您就知道傳值和接值佔去了程式設計師多少時間,也容易造成了相當多的錯誤。

        除此以外,Web Form的出現,為網際網路程式設計帶來底下幾個革命性的發展:

n   網頁和控制項的物件化:
您會發現,使用.NET開發Web應用程式非常接近Visual Basic開發Windows應用程式的方式,網頁和控制項被物件化,這樣程式設計師對於網頁和網頁上的控制項能夠更靈活的操作,撰寫程式也更加地容易。
n   可用Event-Driven的概念撰寫程式:
以前在網頁上寫程式,本質上是Script概念,沒有『按了哪個按鈕,或是點選哪個控制項,就做哪一件事情』這種Event-Driven概念。然而Event-Driven概念是Windows介面上行之有年的程式設計觀念,許多熟悉Windows應用程式設計的讀者就知道,Event-Driven觀念對於物件導向程式設計有著相當大的幫助,不僅加快程式設計速度,也容易維護程式,且提高程式的可讀性。
n   網頁和程式碼分離(Code Behind)
過去的ASP程式和網頁是連體嬰, HTML碼中有程式,程式碼中有HTML的情況隨處可見,加上ASP沒有Event-Driven觀念(在此種『連體』情況中也不可能達成Event-Driven),因此系統愈寫愈大之後,將會變得相當難以維護。而ASP.NET則靠著Code Behind達成網頁與程式碼分離的架構(雖然分離,但卻可以緊密合作)。不僅便於程式維護,此架構對於達成Event-Driven概念有著絕對的幫助。
        除了上述幾個重點之外,Web Form的出現,對於程式設計師來說,有效的縮短了開發時程,透過剛才提到的幾個重點,同樣的一支程式,在ASP可能需要兩三天時間撰寫,到了ASP.NET,可能只需要一個下午,這是筆者親身體驗,我們在後面的實例中會逐漸體驗到ASP.NET的強大。

        透過這兩個實例比較之後,您應該不難發現,ASP.NET的設計架構,完全以Web Form為基底,然後透過操作Web Form,和Web Form上面的Web控制項(其實還有HTML控制項,容後在述)來達成需要的功能,因此我們會在後面詳細的介紹Web Form這個物件。

        在這個段流程中,會涉及三個網頁的運作,我們先稱之為A網頁(Login.asp)B網頁(Check.asp)C網頁(Process.asp)
        這三個網頁的功能分別是:
n   A網頁:提供讓使用者輸入帳號密碼的畫面,網頁中包含<FORM>
n   B網頁:使用者在A網頁輸入帳號密碼後,按下[登入]鈕,會從A網頁Submit到此網頁,在此網頁中透過Request.Form(“xxx”)接收A網頁傳來的值,然後進行檢查帳號密碼的工作。
n   C網頁:包含使用者真正要執行的功能,亦包含檢查是否已經登入過的程式。

        在上面這個流程中,很多程式設計師習慣把A網頁和B網頁合併,由於B網頁本身沒有介面,只有程式,因此將A網頁和B網頁合併的設計方式將較為簡便,在此種方式下,A網頁中的<FORM>架構依舊存在,而僅僅將B網頁中檢查帳號密碼的程式碼,移到A網頁上來執行(一般來說習慣放在A網頁最上方),形成A網頁自己(供使用者輸入帳號密碼後)Submit給自己(來判斷帳號密碼),若密碼正確再轉址到C網頁的情況。

        C網頁則是需要被保護的網頁,是通過帳號密碼檢查才能看到的,該網頁除了原本要呈現的資料之外,還需包含一段檢查使用者是否已經登入過的程式。

過去ASP時代,實際程式約莫如下:

Login.asp
0001:<% ‘底下這段原本應該是 check.asp ,很多程式設計師習慣和 login.asp合併在一起
0002:dim Account
0003:dim Password
0004:
0005:Account=Request.form("UserAccount")
0006:Password=Request.form("Password")
0007:
0008:'檢查帳號密碼程式
0009:if Account="Milk_Lin" and Password="good" then
0010:    '設定 session 表示使用者已經 login
0011:    session("isLogin")=true
0012:   
0013:    '轉到實際被保護的網頁
0014:    response.redirect("Process.asp")
0015:end if
0016:%>
0017:<html>
0018:<head>
0019:<title>登入</title>
0020:</head>
0021:<body>
0022:<form method="POST" action="login.asp">
0023:  <table border="0" width="100%">
0024:    <tr>
0025:      <td width="35%" align="right"></td>
0026:      <td width="65%"></td>
0027:    </tr>
0028:    <tr>
0029:      <td width="35%" align="right">帳號:</td>
0030:      <td width="65%"><input type="text" name="UserAccount" size="20"></td>
0031:    </tr>
0032:    <tr>
0033:      <td width="35%" align="right">密碼:</td>
0034:      <td width="65%"><input type="password" name="password" size="20"></td>
0035:    </tr>
0036:    <tr>
0037:      <td width="35%" align="right"></td>
0038:      <td width="65%"><input type="submit" value="提交" name="B1"></td>
0039:    </tr>
0040:  </table>
0041:</form>
0042:</body>
0043:</html>

沒有留言:

張貼留言