BLL レベルと DAL レベルの例外を処理する (VB)
このチュートリアルでは、編集可能な DataList の更新ワークフロー中に発生した例外を適切に処理する方法について説明します。
はじめに
DataList チュートリアルの「データの編集と削除の概要」では、簡単な編集および削除機能を提供する DataList を作成しました。 完全に機能している間は、編集または削除プロセス中に発生したエラーによってハンドルされない例外が発生したため、ほとんど使い勝手が良くなかったです。 たとえば、製品名を省略したり、製品を編集するときに価格の値を 「とても手頃な価格」と入力すると、例外がスローされます。 この例外はコードではキャッチされないため、ASP.NET ランタイムにバブル アップされ、Web ページに例外の詳細が表示されます。
「ASP.NET ページでの BLL および DAL-Level 例外の処理」チュートリアルで説明したように、ビジネス ロジックまたはデータ アクセス 層の深さから例外が発生した場合、例外の詳細は ObjectDataSource に返され、GridView に返されます。 ObjectDataSource または GridView の イベント ハンドラーまたは RowUpdated
イベント ハンドラーをUpdated
作成し、例外を確認し、例外が処理されたことを示すことで、これらの例外を適切に処理する方法を確認しました。
ただし、DataList チュートリアルでは、データの更新と削除に ObjectDataSource を使用していません。 代わりに、BLL に対して直接作業しています。 BLL または DAL から発生する例外を検出するには、ASP.NET ページの分離コード内に例外処理コードを実装する必要があります。 このチュートリアルでは、編集可能な DataList の更新ワークフロー中に発生した例外をより適切に処理する方法について説明します。
注意
DataList チュートリアルの「データの編集と削除の概要」では、DataList からデータを編集および削除するためのさまざまな手法について説明しました。更新と削除に ObjectDataSource を使用する場合に関連するいくつかの手法について説明しました。 これらの手法を使用する場合は、ObjectDataSource Updated
またはイベント ハンドラーを使用して BLL または Deleted
DAL からの例外を処理できます。
手順 1: 編集可能な DataList を作成する
更新ワークフロー中に発生する例外の処理について心配する前に、まず編集可能な DataList を作成しましょう。 フォルダー内のページをEditDeleteDataList
ErrorHandling.aspx
開き、DataList をDesignerに追加し、そのID
プロパティを にProducts
設定して、 という名前ProductsDataSource
の新しい ObjectDataSource を追加します。 クラス s GetProducts()
メソッドを使用ProductsBLL
してレコードを選択するように ObjectDataSource を構成します。INSERT、UPDATE、DELETE タブのドロップダウン リストを (None) に設定します。
図 1: メソッドを使用して製品情報を GetProducts()
返す (クリックするとフルサイズの画像が表示されます)
ObjectDataSource ウィザードが完了すると、Visual Studio によって DataList の が ItemTemplate
自動的に作成されます。 これを ItemTemplate
、各製品の名前と価格を表示し、[編集] ボタンを含む に置き換えます。 次に EditItemTemplate
、名前と価格と [更新] ボタンと [キャンセル] ボタンの TextBox Web コントロールを使用して を作成します。 最後に、DataList の 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
イベントのイベント ハンドラーを作成する必要があります。 イベントと CancelCommand
イベントはEditCommand
、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
イベント ハンドラーはもう少し複雑です。 の TextBoxes EditItemTemplate
から製品の名前と価格と共にコレクションからDataKeys
編集された製品ProductID
を読み取り、DataList を事前編集状態に戻す前にクラス s UpdateProduct
メソッドを呼び出ProductsBLL
す必要があります。
ここでは、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 は例外を発生させます。
例外が発生した場合は、ページ自体に有益なメッセージを表示します。 が に設定されている ID
ページに Label Web コントロールを追加します ExceptionDetails
。 ラベルのテキストを、ファイルで定義されている CSS クラスにプロパティWarning
をCssClass
割り当てることで、赤、特大、太字、斜体のフォントでStyles.css
表示するように構成します。
エラーが発生した場合は、ラベルを 1 回だけ表示します。 つまり、後続のポストバックでは、ラベルの警告メッセージは表示されなくなります。 これは、イベント ハンドラーで Label のText
プロパティをクリアするか、イベント Visible
ハンドラーでそのプロパティを にFalse
設定するか (「ASP.NET ページでのPage_Load
例外の処理」および「ASP.NET ページの例外の DAL-Level」チュートリアルで行ったように)、またはラベルのビューステートのサポートを無効にすることで実現できます。 後者のオプションを使用してみましょう。
<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
runat="server" />
例外が発生したら、例外の詳細を Label コントロールの Text
プロパティにExceptionDetails
割り当てます。 ビュー ステートが無効になっているため、後続のポストバック Text
では、プロパティのプログラムによる変更が失われるので、既定のテキスト (空の文字列) に戻り、警告メッセージが非表示になります。
ページに役立つメッセージを表示するためにエラーが発生したタイミングを判断するには、イベント ハンドラーにブロックを Try ... Catch
追加する UpdateCommand
必要があります。 部分には Try
例外につながる可能性のあるコードが含まれていますが、 Catch
ブロックには例外が発生した場合に実行されるコードが含まれています。 ブロックの詳細については、.NET Frameworkドキュメントの例外処理の基礎に関するセクションをTry ... Catch
参照してください。
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
がスローされます。 、、UnitsOnOrder
または ReorderLevel
フィールドに無効な値が入力されたUnitPrice
UnitsInStock
場合は、 ArgumentException
クラスでProductsDataTable
これらのフィールド値を検証するコードを追加すると、 がスローされます (「ビジネス ロジック レイヤーの作成」チュートリアルを参照してください)。
キャッチされた例外の種類に基づいてメッセージ テキストを基にすることで、エンド ユーザーにより役立つ説明を提供できます。 「 ASP.NET Page での BLL と DAL-Level 例外の処理 」チュートリアルでほぼ同じ形式で使用されていた次のコードは、この詳細レベルを提供します。
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
このチュートリアルを完了するには、キャッチException
されたインスタンス (ex
) をDisplayExceptionDetails
渡す ブロックから Catch
メソッドを呼び出します。
ブロックを Try ... Catch
配置すると、図 4 と図 5 に示すように、より有益なエラー メッセージがユーザーに表示されます。 例外が発生した場合、DataList は編集モードのままであることに注意してください。 これは、例外が発生すると、制御フローがブロックに Catch
直ちにリダイレクトされ、DataList を編集前の状態に戻すコードをバイパスするためです。
図 4: ユーザーが必須フィールドを省略した場合にエラー メッセージが表示される (フルサイズの画像を表示する場合にクリックします)
図 5: 負の価格を入力するとエラー メッセージが表示される (フルサイズの画像を表示する をクリックします)
まとめ
GridView と ObjectDataSource には、ワークフローの更新と削除中に発生したすべての例外に関する情報と、例外が処理されたかどうかを示すために設定できるプロパティを含む、ポストレベルのイベント ハンドラーが用意されています。 ただし、これらの機能は、DataList を操作し、BLL を直接使用する場合は使用できません。 代わりに、例外処理を実装する責任があります。
このチュートリアルでは、イベント ハンドラーに ブロックを追加して、編集可能な DataList の更新ワークフローに例外処理を追加 Try ... Catch
する方法について UpdateCommand
説明しました。 更新ワークフロー中に例外が発生した場合、 Catch
ブロックのコードが実行され、ラベルに役立つ情報が ExceptionDetails
表示されます。
この時点で、DataList は例外が最初に発生しないように努力しません。 負の価格が例外になることがわかっている場合でも、ユーザーがこのような無効な入力を事前に入力できないようにする機能はまだ追加されていません。 次のチュートリアルでは、 に検証コントロールを追加することで、無効なユーザー入力によって発生する例外を EditItemTemplate
減らす方法について説明します。
プログラミングに満足!
もっと読む
このチュートリアルで説明するトピックの詳細については、次のリソースを参照してください。
- 例外のデザインのガイドライン
- エラー ログ モジュールとハンドラー (ELMAH) ( エラーをログ記録するためのオープンソース ライブラリ)
- .NET Framework 2.0 用エンタープライズ ライブラリ (例外管理アプリケーション ブロックを含む)
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。
特別な感謝
このチュートリアル シリーズは、多くの役立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は Ken Pespisa でした。 今後の MSDN 記事の確認に関心がありますか? その場合は、 に行mitchell@4GuysFromRolla.comをドロップしてください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示