6

私は3層ベースのWebアプリケーションを持っています。使用したいビジネスロジック層でtrycatchブロックを使用しています。ビジネスロジックでtry/catchブロックを使用するのは正しいですか、それともUIレイヤーで使用する必要がありますか?

DALの私のコードを参照してください。

Data Access Layer

#region Insert in to Logbook
public int Insert_LogBook(string Vehicle_Number, DateTime Vehicle_Booking_Date, TimeSpan Time_From, TimeSpan Time_To, int KM_Start, int KM_End, string Vehicle_Used_By, string Cost_Code, string Budget_Line, DateTime Entry_Date)
{
    try
    {
        SqlCommand com = new SqlCommand("Insert_LogBook", con);
        com.Parameters.Add("@Vehicle_Number", SqlDbType.NVarChar, 100).Value = Vehicle_Number;
        com.Parameters.Add("@Vehicle_Booking_Date", SqlDbType.DateTime).Value = Vehicle_Booking_Date;
        com.Parameters.Add("@Time_From", SqlDbType.Time).Value = Time_From;
        com.Parameters.Add("@Time_To", SqlDbType.Time).Value = Time_To;
        com.Parameters.Add("@KM_Start", SqlDbType.Int).Value = KM_Start;
        com.Parameters.Add("@KM_End", SqlDbType.Int).Value = KM_End;
        com.Parameters.Add("@Vehicle_Used_Byr", SqlDbType.VarChar, 100).Value = Vehicle_Used_By;
        com.Parameters.Add("@Cost_Code", SqlDbType.NVarChar, 50).Value = Cost_Code;
        com.Parameters.Add("@Budget_Line", SqlDbType.NVarChar, 50).Value = Budget_Line;
        com.Parameters.Add("@Entry_Date", SqlDbType.DateTime).Value = Entry_Date;
        con.Open();
        int res = com.ExecuteNonQuery();

    }
    catch (Exception ex)
    {
        WebMsgBox.Show(ex.Message);
    }
    finally
    {
        con.Close();
        con.Dispose();

    }
    return 1;
}
#endregion

だから私はそれを私のbalまたはINUIレイヤーで使用する必要がありますか、それとも私のコードは大丈夫です。UIレイヤーでtry/catchを使用しない場合、例外をキャッチせず(存在する場合)、エラーページが表示されるためです。

4

4 に答える 4

6

例外処理とスローは、私が一緒に仕事をしたほとんどの開発者によって、私がいつも誤解しているものです。

  • 例外を使用すると、コードのバグを見つけることができます。
  • 彼らは、ビジネスへの「怪我」を防ぐために実行中のプログラムを停止します。
  • これらを使用すると、合理的に予想される例外(モバイルアプリでネットワークを利用できない)とNullReferenceExceptionなどの予期しないバグ例外をフィルタリングできます。
  • 彼らは、エラーが発生した理由について真っ直ぐに理解します。
  • これにより、各コンポーネントは、デバッグに役立つコンテキストと状態に関する情報のレイヤーを追加できます。これは、キャッチ、ラップ、およびスローのパターンです。

try / catch /(finally)はほとんどどこでも使用でき、使用する必要がありますが...

catchを使用するのは、発生する可能性が高く、それらから回復できる例外がわかっている場合のみです。基本の例外タイプをキャッチすることはめったにありません。他のすべてのエラーが発生し、プログラマー/テスター/ユーザーが見つけられるようにします。

別の例外をスローし、元の例外をInnerExceptionとしてアタッチする場合は、基本例外タイプをキャッチすることをお勧めします。

独自の例外タイプを作成することについて、よく考えたり、怠惰になったりしないでください。たとえば、DataAccessExceptionを記述し、InnerExceptionでアタッチされた層内でキャッチされた例外を使用してそれをスローしたい場合があります。このように、ロギングはエラーが発生した場所をより正確に示す例外タイプをログに記録し、呼び出し元のコードはDataAccessExceptionをキャッチして再試行などを実行することのみを選択できます。

DataAccessExceptionを抽象化し、SqlDataAccessExceptionやSecurityDataAccessExceptionなどのより具体的な例外をサブクラス化することも検討できます。

ご存知のように、例外自体をキャッチして処理しなくても、エラーが発生した場合にコードが確実に実行されるようにする場合は、finallyを使用します。常にリソースを解放する必要がある状況では、try/finallyが標準パターンになります。

また、可能であれば、エラーを処理できる最も具体的なコードのパッチの周りにtry / catchを配置して、周囲のコードのコーディングバグがアプリをクラッシュさせるようにします。

「どの例外がスローされるかまだわからない場合、どうすれば特定の例外をキャッチできますか?」と思うかもしれません。それらがExecuteNonSqlメソッドで文書化されていることを確認する必要があります。そのため、スローされる例外を除いて、独自のAPI/コンポーネントを文書化することが非常に重要です。XMLコメントを使用してこれを行い、パブリックDLLを出荷する場合は、XMLコメントファイルジェネレータをオンにします。

これは理解するのが大変なように思えるかもしれませんが、実際にはそうではありません。ロギングと適切な例外処理/スローに投資すると、数分でバグを解決できるようになり、チャンピオンのように感じ、すぐに他のみんなの貧弱なコードに腹を立てることを学ぶでしょう:)

プログラミング生活のこの段階では、CwalinaとAbramsによるフレームワーク設計ガイドラインを読むことを強くお勧めします。これは、これらすべてのタイプの質問について迅速に正しい選択を行うのに役立ち、独自のコードを使用することは、MicrosoftのAPIを使用するのと同じくらい楽しいことがわかります(ほとんどの場合)。

ルーク

メッセージについて少し追加します。私はエラーメッセージでこの種のものを使用します。

「{一部の機能を実行できません}。{例外の種類}が発生しました。{修正アドバイスまたはエラーの一般的な理由を提供してください}。{内部例外|その他のログエントリ}をご覧ください。」

たとえば、アプリの状態を自動保存するためのコンポーネントでは、次のようになります。

...
catch(FileNotFoundException fnfe)
{
    string m = String.Format("Cannot save changes. A FileNotFoundException occurred. Check the path '{0}' is valid, that your network is up, and any removable media is available. Please see inner exception.", path);

    _log.Error(m, fnfe);

    throw new StorageLifecycleException(m, fnfe);
}
于 2013-02-21T10:04:03.413 に答える
4

状況によって異なりますがtry catch、両方のレイヤーでブロックを使用できます。

ただし、問題は、例外処理コードを使用している場所ではありません。問題はあなたがどのように使っているかです。ジェネリックをキャッチしていると提供した例exceptionでは、それがSqlExceptionであるか、その他の例外であるかはわかりません。

一般に、

  1. 処理できる例外のみをキャッチします(catchの例SqlExceptionでは、すべての例外ではありません)

  2. ユーザーフレンドリーなメッセージを表示する(この例では、エラーメッセージを表示するだけではユーザーには意味がありません)

  3. 例外をログに記録する

  4. 発生した例外を処理します。DAL関連の例外の場合はDALレイヤーで処理し、UI関連の例外の場合はUIレイヤーで処理します。

于 2013-02-21T09:27:31.987 に答える
2

例外を処理できるtry-catchブロックを作成する必要があります。「常にトライキャッチをここかそこに置く」というようなものはありません。私はあなたがこのように例外を処理するのを見ます:

catch (Exception ex)
{
    WebMsgBox.Show(ex.Message);
}

これはいくつかの理由で悪いです:

  1. ジェネリックException型をキャッチします。私は数日前にこれについての質問を見ました:https ://stackoverflow.com/a/14727026/238682
  2. WebMsgBox.Showデータアクセス層内で例外を処理しようとします。これにより、層の境界が破られます。

この例のもう1つの問題は小さな問題ですが、長期的には重要だと思います(全体的なコード設計)。エラー処理ロジックを実際のアプリケーションロジックから分離する必要があります。したがって、try-catchブロックを使用するときは、その中のロジックを最小化して、コードが読みやすくなるようにしてください。

public int Insert_LogBook(string Vehicle_Number, DateTime Vehicle_Booking_Date, TimeSpan Time_From, TimeSpan Time_To, int KM_Start, int KM_End, string Vehicle_Used_By, string Cost_Code, string Budget_Line, DateTime Entry_Date)
{
    using(SqlCommand com = new SqlCommand("Insert_LogBook", con))
    {
        com.Parameters.Add("@Vehicle_Number", SqlDbType.NVarChar, 100).Value = Vehicle_Number;
        com.Parameters.Add("@Vehicle_Booking_Date", SqlDbType.DateTime).Value = Vehicle_Booking_Date;
        com.Parameters.Add("@Time_From", SqlDbType.Time).Value = Time_From;
        com.Parameters.Add("@Time_To", SqlDbType.Time).Value = Time_To;
        com.Parameters.Add("@KM_Start", SqlDbType.Int).Value = KM_Start;
        com.Parameters.Add("@KM_End", SqlDbType.Int).Value = KM_End;
        com.Parameters.Add("@Vehicle_Used_Byr", SqlDbType.VarChar, 100).Value = Vehicle_Used_By;
        com.Parameters.Add("@Cost_Code", SqlDbType.NVarChar, 50).Value = Cost_Code;
        com.Parameters.Add("@Budget_Line", SqlDbType.NVarChar, 50).Value = Budget_Line;
        com.Parameters.Add("@Entry_Date", SqlDbType.DateTime).Value = Entry_Date;
        con.Open();
        int res = com.ExecuteNonQuery();

        return 1;
    }

}

public void SomeMethodWhichUsesThatInsert()
{
    try
    {
        //call Insert_LogBook
    }
    catch(SomeException e)
    {
        //handle
    }

}
于 2013-02-21T09:27:05.087 に答える
0

データアクセスとビジネスロジックをクラスライブラリに配置する必要があります。BLLまたはDALからフロントエンドコンポーネントを呼び出さないでください。ここにlog4netputエラーデータのようなものを使用して、BLLおよびDALログにログを作成します。

次に、エラー状態をユーザーに通知する場合は、例外を上方にスローします。

于 2013-02-21T09:26:57.517 に答える