BLL レベルと DAL レベルの例外を処理する (VB)

作成者: Scott Mitchell

PDF のダウンロード

このチュートリアルでは、編集可能な 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 を作成しましょう。 フォルダー内のページをEditDeleteDataListErrorHandling.aspx開き、DataList をDesignerに追加し、そのIDプロパティを にProducts設定して、 という名前ProductsDataSourceの新しい ObjectDataSource を追加します。 クラス s GetProducts() メソッドを使用ProductsBLLしてレコードを選択するように ObjectDataSource を構成します。INSERT、UPDATE、DELETE タブのドロップダウン リストを (None) に設定します。

GetProducts() メソッドを使用して製品情報を返す

図 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 の EditCommandCancelCommand、、および 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 クラスにプロパティWarningCssClass割り当てることで、赤、特大、太字、斜体のフォントで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 ブロックのコードの実行が開始されます。 、などによってスローされるDbExceptionNoNullAllowedExceptionArgumentException例外の種類は、最初にエラーが発生した内容によって異なります。 データベース レベルで問題が発生した場合は、 DbException がスローされます。 、、UnitsOnOrderまたは ReorderLevel フィールドに無効な値が入力されたUnitPriceUnitsInStock場合は、 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減らす方法について説明します。

プログラミングに満足!

もっと読む

このチュートリアルで説明するトピックの詳細については、次のリソースを参照してください。

著者について

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をドロップしてください。