處理 BLL 和 DAL 層級的例外狀況 (VB)
在本教學課程中,我們將瞭解如何在可編輯的 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 索引標籤中的下拉式清單設定為 [無]。
圖 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 、 EditCommand
CancelCommand
和 UpdateCommand
事件的事件處理程式。 EditCommand
和 CancelCommand
事件只會更新 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
以及 中 EditItemTemplate
TextBoxes 的產品名稱和價格,然後呼叫 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 控制項新增至設定為 的頁面ID
ExceptionDetails
。 將標籤 CssClass
的文字指派給 Warning
檔案中 Styles.css
定義的 CSS 類別,設定標籤文字以紅色、大、粗體和斜體字型顯示。
發生錯誤時,我們只想要顯示標籤一次。 也就是說,在後續回傳時,標籤的警告訊息應該會消失。 這可以藉由清除 Label 的 Text
屬性或在事件處理程式中將其屬性設定Visible
為 False
來完成(如同我們在 ASP.NET 頁面教學課程中Page_Load
處理 BLL 和 DAL 層級例外狀況一樣),或停用卷標的檢視狀態支援。 讓我們使用後者選項。
<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
runat="server" />
引發例外狀況時,我們會將例外狀況的詳細數據指派給 ExceptionDetails
Label 控件的 Text
屬性。 由於其檢視狀態已停用,因此在後續回傳 Text
時,屬性的程式設計變更將會遺失,並還原回默認文字(空字串),從而隱藏警告訊息。
若要判斷何時引發錯誤,以便在頁面上顯示有用的訊息,我們需要將區塊新增 Try ... Catch
至 UpdateCommand
事件處理程式。 部分 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
區塊的程序代碼就會開始執行。 擲回 DbException
、 NoNullAllowedException
、 ArgumentException
等的例外狀況類型取決於第一次擷取錯誤的內容。 如果資料庫層級發生問題, DbException
將會擲回 。 如果針對、 、 或欄位輸入UnitPrice
了非法值,ArgumentException
會擲回 ,因為我們已新增程式代碼來驗證 類別中的ProductsDataTable
這些域值(請參閱建立商業規則層教學課程)。ReorderLevel
UnitsOnOrder
UnitsInStock
我們可以藉由根據攔截到的例外狀況類型來提供更實用的說明給終端使用者。 下列程式代碼在處理 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
新增驗證控件,協助減少使用者輸入無效所造成的例外狀況。
快樂程式!
深入閱讀
有關本教學課程中討論的主題的更多資訊,請參閱以下資源:
- 例外狀況的設計方針
- 錯誤記錄模組和處理程式 (ELMAH) (用於記錄錯誤的開放原始碼連結庫)
- 適用於 .NET Framework 2.0 的企業連結庫(包括例外狀況管理應用程式區塊)
關於作者
Scott Mitchell,七本 ASP/ASP.NET 書籍的作者和 4GuysFromRolla.com 創始人,自 1998 年以來便開始使用 Microsoft Web 技術。 Scott 擔任獨立顧問、講師和作家。 他的新書是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 您可以透過 mitchell@4GuysFromRolla.com 或他的部落格 (可以在 http://ScottOnWriting.NET 找到) 與他聯繫。
特別感謝
本教學課程系列已經過許多熱心的檢閱者檢閱。 本教學課程的主要檢閱者是 Ken Pespisa。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果有,請發信到 mitchell@4GuysFromRolla.com 。