導言
到目前為止的討論編輯DataList的教程裡,沒有包含任何驗證用戶的輸入,即使是用戶非法輸入— 遺漏了product的name或者負的price— 會導致異常。在前面一章裡我們學習了如何在DataList的UpdateCommand事件處理中添加異常處理代碼,以便在出現異常時捕捉它並顯示友好的錯誤信息。然而理想的編輯界面應該包含驗證控件,用來在第一時間裡阻止用戶輸入一些非法數據。
本章我們將學習在DataList的EditItemTemplate裡添加驗證控件從而提供一個更安全的編輯界面,這非常容易。本章將使用前面創建的例子,並擴展編輯界面用來添加合適的驗證控件。
第一步: 從 處理 BLL和 DAL的異常復制例子
在處理BLL和DAL的異常裡我們創建了一個以兩列的方式列出product的name和price的DataList。本章的目標是擴展這個DataList的編輯界面,讓它包含驗證控件。我們的驗證邏輯如下:
product的 name 是必填的
確保輸入的price的值是合法的貨幣類型格式
確保輸入的price的值大於等於0
我們首先需要將ErrorHandling.aspx頁的例子復制到UIValidation.aspx裡。這其中包括頁面的聲明代碼和後台代碼。下面是復制聲明代碼的步驟:
在Visual Studio的打開 ErrorHandling.aspx 切換到源視圖 復制從 <asp:Content> 到</asp:Content> 標簽內的代碼, 見圖1.
圖 1: 復制<asp:Content> 內的代碼
打開UIValidation.aspx 切換到源視圖 ,粘貼代碼.
完成上面的步驟後,打開ErrorHandling.asxp.cs,復制DispalyExcetionDetails方法和三個事件處理(Products_EditCommand,Products_CancelCommand, 和Products_UpdateCommand),注意不要復制聲明類和using的代碼。將這些代碼粘貼到ErrorHandling.asxp.cs裡的EditDeleteDataList_UIValidation 類裡。完成這些後,浏覽一下頁面。這兩個頁面無論是輸出還是功能都是一樣的(見圖2)。
圖 2: UIValidation.aspx 頁ErrorHandling.aspx一樣
第二步: 為DataList的 EditItemTemplate添加驗證控件
當創建輸入表格時,很重要的一點是聲明必填字段和用戶的輸入必須是格式正確的合法值。為了確保用戶輸入是合法的,ASP.NET提供了5個內置的驗證控件,這些驗證控件被設計用來驗證單個的輸入控件裡的輸入值。
RequiredFieldValidator —確保必填值
CompareValidator — 根據另外的控件的值或常量來驗證某個值,或者確保輸入值是特定的類型
RangeValidator — 確保輸入值在某個范圍內
RegularExpressionValidator — 根據正則表達式( regular expression )來驗證某個值
CustomValidator — 根據用戶自定義的方法來驗證某個值
更多的關於這5個控件的信息請參考給編輯和新增界面增加驗證控件 或著ASP.NET Quickstart Tutorials裡的Validation Controls section。
本章裡我們需要使用RequiredFieldValidator 來確保用戶輸入了product的name,CompareValidator 來確保price的值大於等於0並且是合法的貨幣格式。
注意:在ASP.NET 1.x裡已經包含了這些驗證控件了,在ASP.NET 2.0裡對它們有很多改進。其中最重要的兩點一是對除了IE之外的浏覽器的客戶端腳本支持,二是同一頁面上的驗證控件分組。更多的2.0裡驗證控件新特性的信息請參考Dissecting the Validation Controls in ASP.NET 2.0.
現在我們來將需要的驗證控件添加到DataList的EditItemTemplate裡。這個可以通過點擊DataList智能標簽上的Edit Template,或者直接寫聲明代碼來完成。我們這裡使用第一種方法。選擇Edit Template後拖一個RequiredFieldValidator 進來,將它放在ProductName TextBox後面。
圖 3: 添加 RequiredFieldValidator
所有的驗證控件都只驗證單個的Web控件。因此我們需要指明剛添加的RequiredFieldValidator 是用來驗證ProductName TextBox。這個關聯是通過將驗證控件的ControlToValidate property設為合適的Web控件(在這裡是ProductName).然後將ErrorMessage property設為“You must provide the product's name”,Text property設為“*”。如果提供了Text屬性的值,它將在驗證失敗時顯示。ErrorMessage 屬性是提供給ValidationSummary 控件使用的。如果省略了Text的值,在非法輸入時會顯示 ErrorMessage 。完成這些後你的頁面看起來應該和圖4差不多:
圖 4: 設置 RequiredFieldValidator的 ControlToValidate, ErrorMessage, 和Text Properties
添加完RequiredFieldValidator 後,剩下的事就是為product的price添加驗證控件了。由於編輯時UnitPrice屬於可選項,所以我們不用添加RequiredFieldValidator。我們需要做的是添加一個CompareValidator 來保證在輸入了price的情況下,它的值是正確的貨幣格式和大於等於0。
為EditIteTemplate添加一個ControlToValidate 屬性為UnitPrice的CompareValidator 。將ErrorMessage 設為“The price must be greater than or equal to zero and cannot include the currency symbol”,Text設為“*”。為了指定UnitPrice的值必須大於等於0,將CompareValidator的Operator property設為GreaterThanEqual,ValueToCompare property設為“0”,Type property設為Currency。添加完這兩個驗證控件後,DataList的EditItemTemplate聲明代碼應該和下面差不多:
<EditItemTemplate> Product name: <asp:TextBox ID="ProductName" runat="server" Text='<%# Eval("ProductName") %>'></asp:TextBox> <asp:RequiredFieldValidator ID="RequiredFieldValidator1" ControlToValidate="ProductName" ErrorMessage="You must provide the product's name" runat="server">*</asp:RequiredFieldValidator> <br /> Price: <asp:TextBox ID="UnitPrice" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:TextBox> <asp:CompareValidator ID="CompareValidator1" ControlToValidate="UnitPrice" ErrorMessage="The price must be greater than or equal to zero and cannot include the currency symbol" Operator="GreaterThanEqual" Type="Currency" ValueToCompare="0" runat="server">*</asp:CompareValidator><br /> <br /> <asp:Button ID="UpdateProduct" runat="server" CommandName="Update" Text="Update" /> <asp:Button ID="CancelUpdate" runat="server" CommandName="Cancel" Text="Cancel" /> </EditItemTemplate>
浏覽一下頁面。現在如果你編輯的時候不輸入name或者在price裡輸入一個非法的值,在textbox後面會出現一個“*”。見圖5。一個包含貨幣符號的值—比如$19.95 —被認為是合法的。CompareValidator的Currency 類型允許數字分隔符(比如句號和逗號)和前面帶"+"或"-"號,但是不允許帶貨幣符號。而在編輯界面裡的UnitPrice又會以貨幣格式展現,這可能會讓用戶感到困惑。
圖 5: 非法輸入 Textboxes 後面會出現“*”
當驗證控件象上面這樣工作時,用戶在編輯時需要手工移除掉貨幣符號,這是不可接受的。而且,如果在編輯的時候有非法輸入,不管是點Update還是Cancel button,頁面都會postback。理想的情況是,點Cancel button會返回DataList的編輯前狀態,而不管輸入的值是否合法。當然由於用戶的浏覽器可能不支持JavaScript 或者被禁用了,在更新product信息前我們要在UpdateCommand事件處理裡確保頁面的數據都是合法的。
從EditItemTemplate的UnitPrice TextBox裡移除貨幣符號
當使用CompareValidator的貨幣類型時,輸入不能包含任何貨幣符號,否則CompareValidator 會視為非法。然而編輯界面裡的UnitPrice TextBox已經包含了一個貨幣符號,這就意味著用戶在保存前必須手動移除它。我們有三種方法來修補它:
配置EditItemTemplate 使 UnitPrice TextBox 的值的格式不為貨幣. 用RegularExpressionValidator 代替CompareValidator來檢查正確格式的貨幣值 . 這裡的挑戰是用正則表達式不象用CompareValidator 那樣直接,方便,需要寫一些代碼。 移除所有的驗證控件,驗證的功能將完全依賴於服務器端的GridView的RowUpdating事件處理。
我們這裡使用第一種方法。現在UnitPrice為貨幣格式是由於TextBox的綁定表達式<%# Eval("UnitPrice", "{0:c}") %>. 將它修改為 Eval("UnitPrice", "{0:n2}")(允許兩位小數的數字)。這個可以通過點擊DataList裡EditItemTemplate裡的UnitPrice TextBox的Edit DataBindings鏈接或直接修改聲明語法來完成。完成這些後,編輯界面的price格式包含兩種分隔符,逗號和句號。
注意:在移除貨幣格式的時候,我發現將貨幣符號作為text放在TextBox前面是一種好的做法。它會提醒用戶他們不需要再輸入貨幣符號。
修補 Cancel Button
默認情況下,驗證控件生成JavaScript 在客戶端執行驗證。當點擊Button, LinkButton, 或ImageButton時,驗證控件會在頁面postback之前檢查。如果有非法的數據,postback不會發生。然而對某些Button來說,這時並不需要驗證數據。在這樣的情況下,取消了postback是非常討厭的。
Cancel button就屬於這種情況。想象一下用戶輸入了非法的數據,比如忽略了product的name,然後決定他不需要保存product,然後點擊了Cancel button。在這種情況下,Cancel button會觸發驗證控件,它會報告說缺少product的name,並阻止postback。我們的用戶不得不向Product TextBox裡輸入一些文字然後再取消編輯。
幸運的是,Button, LinkButton, 和ImageButton 有CausesValidation property,它可以指明當點擊Button時是否需要發起驗證(默認為True)。將 Cancel Button的CausesValidation 設為False.
在 UpdateCommand Event Handler裡確保輸入是合法的
客戶端的腳本是由驗證控件生成的,如果用戶輸入非法數據,並點擊CausesValidation屬性 為True的button時將不會引起postback。然而如果用戶用戶使用的是版本很低的浏覽器或者禁用了對JavaScript 的支持,那麼客戶端的驗證將不會執行。
頁面postback的時候所有的驗證控件執行驗證,然後將驗證報告提交給Page.IsValid property。然而,整個流程並不會被Page.IsValid的值打斷。作為開發者,我們需要保證在Page.IsValid為True的情況下代碼再繼續運行。
如果禁用了JavaScript 的用戶浏覽我們的頁,編輯了product,在price裡輸入一個“太貴”的值,然後點Update button,客戶端的驗證將被跳過,頁面會繼續postback。UpdateCommand事件處理將執行,隨後在試圖將“太貴”的價格轉換為Decimal時拋出異常。雖然已經寫過異常處理了,但是我們其實可以根據Page.IsValid的值在第一時間裡阻止非法輸入。
在UpdateCommand 的最開始加上下面的代碼:
if (!Page.IsValid) return;
完成這個後,product將只在提交的數據合法時才被更新。大多數用戶的非法提交會由於客戶端腳本而被拒絕postback,而那些浏覽器不支持JavaScript 或禁用了JavaScript 的客戶會跳過客戶端檢查,提交非法數據。
注意:細心的讀者會記起在GridView裡更新數據時,我們並不需要顯式的檢查Page.IsValid 。這是因為GridView已經幫我們完成了這部分工作,即它只在Page.IsValid 為True時才繼續更新。
第三步: Summarizing Data Entry Problems
除了上面提到的5種驗證控件外,ASP.NET還包含ValidationSummary control,它用來顯示那些檢查到非法數據的驗證控件的錯誤信息。這些匯總的數據可以以文本或客戶端消息框的方式顯示。我們現在來添加包含驗證問題匯總信息的客戶端消息框。
拖一個ValidationSummary 進來。由於我們將它配置為以消息框的形式顯示匯總信息,所以它的位置無所謂。將 ShowSummary property設為False, ShowMessageBox property設為True.這樣,所有驗證的錯誤信息會以客戶端消息框的形式顯示。見圖6。
圖 6: 用一個客戶端消息框匯總驗證的錯誤信息
總結
本章我們學習了如何使用驗證控件保證在更新開始前確保用戶的輸入是合法的,從而減少異常的出現。ASP.NET提供了5種驗證控件來檢查特定的控件的輸入並報告是否合法。本章我們使用了其中的兩種 —RequiredFieldValidator 和CompareValidator —來保證product的name是必填的和price是大於等於0的貨幣格式。
在DataList的編輯界面裡加驗證控件只需要簡單的將它們拖到EditItemTemplate裡,然後設置幾個屬性。默認情況下驗證控件自動生成客戶端驗證腳本,當然也提供在postback時的服務器端驗證,並將所有的結果累積保存在Page.IsValid 裡。在點擊Button,LinkButton或ImageButton時,可以將CausesValidation 設為False從而跳過客戶端驗證。在執行任何代碼前,首先需要保證 Page.IsValid 為True.
目前我們學習的DataList的編輯教程都只是簡單的界面— 在TextBox裡顯示name和price。然而編輯界面可以包含各種不同的web控件,比如DropDownLists,Calenda,RadioButtons, CheckBoxes等。我們下章會創建一個包含各種web控件的界面。
祝編程快樂!
作者簡介
本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創始人,自1998年以來一直應用 微軟Web技術。大家可以點擊查看全部教程《[翻譯]Scott Mitchell 的ASP.NET 2.0數據教程》,希望對大家的學習ASP.NET有所幫助。