共用方式為


處理 BLL 和 DAL 層級的例外狀況 (VB)

由斯科特· 米切爾

下載 PDF

在本教學課程中,我們將瞭解如何在可編輯的 DataList 更新工作流程期間處理引發的例外狀況。

簡介

在 DataList 教學課程中編輯和刪除資料的概觀中,我們建立了提供簡單編輯和刪除功能的 DataList 。 雖然功能完全正常,但很難方便使用者使用,因為編輯或刪除程式期間發生的任何錯誤都會導致未處理的例外狀況。 例如,省略產品名稱,或在編輯產品時輸入價格值非常實惠!,擲回例外狀況。 由於此例外狀況未在程式碼中攔截,因此會升至 ASP.NET 運行時間,然後在網頁中顯示例外狀況的詳細數據。

如我們在處理 ASP.NET Page 教學課程中的 BLL 和 DAL 層級例外狀況中所見,如果例外狀況是從商業規則或數據存取層的深度引發,則會將例外狀況詳細數據傳回至 ObjectDataSource,然後傳回至 GridView。 我們已瞭解如何透過建立 Updated ObjectDataSource 或 RowUpdated GridView 的事件處理程式、檢查例外狀況,然後指出已處理例外狀況,以正常處理這些例外狀況。

不過,我們的 DataList 教學課程並未使用 ObjectDataSource 來更新和刪除數據。 相反地,我們正直接針對 BLL 工作。 為了偵測源自 BLL 或 DAL 的例外狀況,我們需要在 ASP.NET 頁面的程式代碼後置內實作例外狀況處理程式代碼。 在本教學課程中,我們將瞭解如何更巧妙地處理在可編輯的 DataList 更新工作流程期間引發的例外狀況。

注意

在 DataList 教學課程中的編輯和刪除資料概觀中,我們討論了從 DataList 編輯和刪除數據的不同技術,其中有些技術涉及使用 ObjectDataSource 進行更新和刪除。 如果您採用這些技術,您可以透過 ObjectDataSource 或 Updated 事件處理程式來處理 BLL 或 Deleted DAL 的例外狀況。

步驟 1:建立可編輯的數據清單

在我們擔心處理更新工作流程期間發生的例外狀況之前,讓我們先建立可編輯的 DataList。 ErrorHandling.aspx開啟資料夾中的頁面EditDeleteDataList、將 DataList 新增至設計工具、將其ID屬性設定為 Products,然後新增名為 ProductsDataSource的新 ObjectDataSource。 將 ObjectDataSource 設定為使用 ProductsBLL 類別 s GetProducts() 方法來選取記錄;將 INSERT、UPDATE 和 DELETE 索引標籤中的下拉式清單設定為 [無]。

使用 GetProducts() 方法傳回產品資訊

圖 1:使用 GetProducts() 方法傳回產品資訊(按兩下以檢視完整大小的影像

完成 ObjectDataSource 精靈之後,Visual Studio 會自動為 DataList 建立 ItemTemplate 。 將它取代為 ItemTemplate ,其中顯示每個產品名稱和價格,並包含 [編輯] 按鈕。 接下來, EditItemTemplate 使用 TextBox Web 控制項建立 ,以取得名稱和價格,以及 [更新] 和 [取消] 按鈕。 最後,將 DataList s RepeatColumns 屬性設定為 2。

這些變更之後,頁面的宣告式標記看起來應該類似下列內容。 請仔細檢查,確定 [編輯]、[取消] 和 [更新] 按鈕的屬性 CommandName 分別設定為 [編輯]、[取消] 和 [更新]。

<asp:DataList ID="Products" runat="server" DataKeyField="ProductID"
    DataSourceID="ProductsDataSource" RepeatColumns="2">
    <ItemTemplate>
        <h5>
            <asp:Label runat="server" ID="ProductNameLabel"
                Text='<%# Eval("ProductName") %>' />
        </h5>
        Price:
            <asp:Label runat="server" ID="Label1"
                Text='<%# Eval("UnitPrice", "{0:C}") %>' />
        <br />
            <asp:Button runat="server" id="EditProduct" CommandName="Edit"
                Text="Edit" />
        <br />
        <br />
    </ItemTemplate>
    <EditItemTemplate>
        Product name:
            <asp:TextBox ID="ProductName" runat="server"
                Text='<%# Eval("ProductName") %>' />
        <br />
        Price:
            <asp:TextBox ID="UnitPrice" runat="server"
                Text='<%# Eval("UnitPrice", "{0:C}") %>' />
        <br />
        <br />
            <asp:Button ID="UpdateProduct" runat="server" CommandName="Update"
                Text="Update" /> 
            <asp:Button ID="CancelUpdate" runat="server" CommandName="Cancel"
                Text="Cancel" />
    </EditItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    OldValuesParameterFormatString="original_{0}">
</asp:ObjectDataSource>

注意

在本教學課程中,必須啟用DataList的檢視狀態。

請花點時間透過瀏覽器檢視我們的進度(請參閱圖 2)。

每個產品都包含編輯按鈕

圖 2:每個產品都包含編輯按鈕(按兩下以檢視完整大小的影像

目前,[編輯] 按鈕只會造成回傳,它尚未讓產品可編輯。 若要啟用編輯,我們需要建立 DataList 、 EditCommandCancelCommandUpdateCommand 事件的事件處理程式。 EditCommandCancelCommand 事件只會更新 DataList 的 EditItemIndex 屬性,並將數據重新系結至 DataList:

Protected Sub Products_EditCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.EditCommand
    ' Set the DataList's EditItemIndex property to the
    ' index of the DataListItem that was clicked
    Products.EditItemIndex = e.Item.ItemIndex
    ' Rebind the data to the DataList
    Products.DataBind()
End Sub
Protected Sub Products_CancelCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.CancelCommand
    ' Set the DataList's EditItemIndex property to -1
    Products.EditItemIndex = -1
    ' Rebind the data to the DataList
    Products.DataBind()
End Sub

UpdateCommand事件處理程式更涉及一點。 它必須從DataKeys集合讀取已編輯的產品,ProductID以及 中 EditItemTemplateTextBoxes 的產品名稱和價格,然後呼叫 ProductsBLL 類別 s UpdateProduct 方法,再將 DataList 傳回其預先編輯狀態。

現在,讓我們只使用 DataList 教學課程中編輯和刪除資料概觀中事件處理程式完全相同的程式代碼UpdateCommand。 我們將新增程序代碼,以正常處理步驟 2 中的例外狀況。

Protected Sub Products_UpdateCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.UpdateCommand
    ' Read in the ProductID from the DataKeys collection
    Dim productID As Integer = Convert.ToInt32(Products.DataKeys(e.Item.ItemIndex))
    ' Read in the product name and price values
    Dim productName As TextBox = CType(e.Item.FindControl("ProductName"), TextBox)
    Dim unitPrice As TextBox = CType(e.Item.FindControl("UnitPrice"), TextBox)
    Dim productNameValue As String = Nothing
    If productName.Text.Trim().Length > 0 Then
        productNameValue = productName.Text.Trim()
    End If
    Dim unitPriceValue As Nullable(Of Decimal) = Nothing
    If unitPrice.Text.Trim().Length > 0 Then
        unitPriceValue = Decimal.Parse(unitPrice.Text.Trim(), _
                         System.Globalization.NumberStyles.Currency)
    End If
    ' Call the ProductsBLL's UpdateProduct method...
    Dim productsAPI As New ProductsBLL()
    productsAPI.UpdateProduct(productNameValue, unitPriceValue, productID)
    ' Revert the DataList back to its pre-editing state
    Products.EditItemIndex = -1
    Products.DataBind()
End Sub

面對可能格式不正確之單價形式的無效輸入,將引發例外狀況的非法單價值,例如 -$5.00,或遺漏產品名稱。 UpdateCommand由於事件處理程式目前未包含任何例外狀況處理程式碼,因此例外狀況會升至 ASP.NET 運行時間,而該運行時間將會顯示給終端使用者(請參閱圖 3)。

發生未處理的例外狀況時,使用者會看到錯誤頁面

圖 3:發生未處理的例外狀況時,使用者會看到錯誤頁面

步驟 2:正常處理 UpdateCommand 事件處理程式中的例外狀況

在更新工作流程期間,事件處理程式、BLL 或 DAL 中可能會發生 UpdateCommand 例外狀況。 例如,如果使用者輸入太貴的價格, Decimal.Parse 事件處理程式中的 UpdateCommand 語句將會擲回 FormatException 例外狀況。 如果使用者省略產品名稱,或價格有負值,DAL 將會引發例外狀況。

發生例外狀況時,我們想要在頁面本身內顯示資訊訊息。 將標籤 Web 控制項新增至設定為 的頁面IDExceptionDetails。 將標籤 CssClass 的文字指派給 Warning 檔案中 Styles.css 定義的 CSS 類別,設定標籤文字以紅色、大、粗體和斜體字型顯示。

發生錯誤時,我們只想要顯示標籤一次。 也就是說,在後續回傳時,標籤的警告訊息應該會消失。 這可以藉由清除 Label 的 Text 屬性或在事件處理程式中將其屬性設定VisibleFalse 來完成(如同我們在 ASP.NET 頁面教學課程中Page_Load處理 BLL 和 DAL 層級例外狀況一樣),或停用卷標的檢視狀態支援。 讓我們使用後者選項。

<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
    runat="server" />

引發例外狀況時,我們會將例外狀況的詳細數據指派給 ExceptionDetails Label 控件的 Text 屬性。 由於其檢視狀態已停用,因此在後續回傳 Text 時,屬性的程式設計變更將會遺失,並還原回默認文字(空字串),從而隱藏警告訊息。

若要判斷何時引發錯誤,以便在頁面上顯示有用的訊息,我們需要將區塊新增 Try ... CatchUpdateCommand 事件處理程式。 部分 Try 包含可能導致例外狀況的程序代碼,而 Catch 區塊則包含面對例外狀況執行的程序代碼。 如需區塊的詳細資訊Try ... Catch,請參閱 .NET Framework 檔中的例外狀況處理基本概念一節。

Protected Sub Products_UpdateCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.UpdateCommand
    ' Handle any exceptions raised during the editing process
    Try
        ' Read in the ProductID from the DataKeys collection
        Dim productID As Integer = _
            Convert.ToInt32(Products.DataKeys(e.Item.ItemIndex))
        ... Some code omitted for brevity ...
    Catch ex As Exception
        ' TODO: Display information about the exception in ExceptionDetails
    End Try
End Sub

當區塊內的 Try 程式代碼擲回任何類型的例外狀況時, Catch 區塊的程序代碼就會開始執行。 擲回 DbExceptionNoNullAllowedExceptionArgumentException等的例外狀況類型取決於第一次擷取錯誤的內容。 如果資料庫層級發生問題, DbException 將會擲回 。 如果針對、 、 或欄位輸入UnitPrice了非法值,ArgumentException會擲回 ,因為我們已新增程式代碼來驗證 類別中的ProductsDataTable這些域值(請參閱建立商業規則層教學課程)。ReorderLevel UnitsOnOrderUnitsInStock

我們可以藉由根據攔截到的例外狀況類型來提供更實用的說明給終端使用者。 下列程式代碼在處理 ASP.NET Page 教學課程中的處理 BLL 和 DAL 層級例外狀況中,使用於幾乎完全相同的格式,提供此層級的詳細數據:

Private Sub DisplayExceptionDetails(ByVal ex As Exception)
    ' Display a user-friendly message
    ExceptionDetails.Text = "There was a problem updating the product. "
    If TypeOf ex Is System.Data.Common.DbException Then
        ExceptionDetails.Text += "Our database is currently experiencing problems." + _
                                 "Please try again later."
    ElseIf TypeOf ex Is System.Data.NoNullAllowedException Then
        ExceptionDetails.Text+="There are one or more required fields that are missing."
    ElseIf TypeOf ex Is ArgumentException Then
        Dim paramName As String = CType(ex, ArgumentException).ParamName
        ExceptionDetails.Text+=String.Concat("The ", paramName, " value is illegal.")
    ElseIf TypeOf ex Is ApplicationException Then
        ExceptionDetails.Text += ex.Message
    End If
End Sub

若要完成本教學課程,只要從Catch傳入已攔截Exception實例的 區塊呼叫 DisplayExceptionDetails 方法即可。ex

Try ... Catch已就地封鎖後,使用者會看到更豐富的錯誤訊息,如圖 4 和 5 所示。 請注意,面對例外狀況,DataList 會維持在編輯模式中。 這是因為發生例外狀況之後,控制流程會立即重新導向至 Catch 區塊,略過傳回 DataList 至其預先編輯狀態的程序代碼。

如果使用者省略必要欄位,就會顯示錯誤訊息

圖 4:如果使用者省略必要字段,就會顯示錯誤訊息(按兩下以檢視完整大小的影像

輸入負價時會顯示錯誤訊息

圖 5:輸入負價時顯示錯誤訊息 (按兩下以檢視完整大小的影像

摘要

GridView 和 ObjectDataSource 提供後置事件處理程式,其中包含更新和刪除工作流程期間引發之任何例外狀況的相關信息,以及可設定為指出是否已處理例外狀況的屬性。 不過,當使用 DataList 並使用 BLL 時,無法使用這些功能。 相反地,我們負責實作例外狀況處理。

在本教學課程中,我們已瞭解如何將區塊新增至事件處理程式,將例外狀況處理新增至UpdateCommand可編輯的 DataList 更新工作流程Try ... Catch。 如果在更新工作流程期間引發例外狀況, Catch 區塊的程序代碼就會執行,並在標籤中 ExceptionDetails 顯示有用的資訊。

此時,DataList 不會盡一切努力防止例外狀況在一開始發生。 雖然我們知道負價會導致例外狀況,但我們尚未新增任何功能,以主動防止使用者輸入這類無效的輸入。 在下一個教學課程中,我們將瞭解如何在 中 EditItemTemplate新增驗證控件,協助減少使用者輸入無效所造成的例外狀況。

快樂的程序設計!

深入閱讀

如需本教學課程中所討論主題的詳細資訊,請參閱下列資源:

關於作者

斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 山姆斯在24小時內 ASP.NET 2.0。 他可以到達 mitchell@4GuysFromRolla.com, 或通過他的博客,可以在 找到 http://ScottOnWriting.NET

特別感謝

本教學課程系列已由許多實用的檢閱者檢閱。 本教學課程的主要檢閱者是 Ken Pespisa。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com放在 。