2

アセンブリ レベルで適用されるPostsharpからのマルチキャスト OnExceptionAspectがあります。これは当然、例外をスローすると、すべてのメソッドがアスペクトを呼び出すことを意味します。

アスペクト内で、例外が発生したときに渡されたパラメーターの値を含む例外の詳細をログに記録していますが、これは正しく機能しています。

ただし、これはアセンブリ内のすべてのメソッドに適用されるため、スタック内のメソッドごとにログ エントリが作成され、例外が各メソッドにバブル アップします。

これを防ぐ方法についてのアイデアがありません。最初は例外を比較して(同じかどうかを確認するために)しようとしていましたが、これは面倒なようです。誰かが以前にこの問題を抱えていたに違いありません。

4

3 に答える 3

4

この問題には2つの解決策があります。

A.スレッド静的フィールドを使用して、すでにログに記録されている例外を保存します。

[Serializable] 
public class MyAspect : OnExceptionAspect 
{ 
    [ThreadStatic]
    private static Exception lastException;

    public override void OnException(MethodExecutionArgs args) 
    { 
      if(args.Exception != lastException) 
      { 
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}",  
            args.Method.Name, DateTime.Now,  
            args.Exception.Message, args.Exception.StackTrace); 

        Trace.WriteLine(msg); 
        lastException = args.Exception;
      } 

    }  
}

B.Exceptionオブジェクトにタグを追加します。

[Serializable] 
public class MyAspect : OnExceptionAspect 
{ 
    private static object marker = new object();

    public override void OnException(MethodExecutionArgs args) 
    { 
      if(!args.Exception.Data.Contains(marker)) 
      { 
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}",  
            args.Method.Name, DateTime.Now,  
            args.Exception.Message, args.Exception.StackTrace); 

        Trace.WriteLine(msg); 
        args.Exception.Data.Add(marker, marker);
      } 

    }  
}
于 2012-04-26T07:57:33.487 に答える
3

参考までに--ゲールはそこで雇用されているため、ポストシャープの第一人者です...ちょうどあなたが知っているように。

価値があるのは、StackTrace を調べることで、いつでも例外が発生した場所を知ることができるということです。StackTrace は、args.Exception.StackTrace を介して利用可能になります。ダスティン・デイビス (別の PostSharp 従業員) がここで推奨することを試すことができます: PostSharp - OnExceptionAspect - 例外の行番号を取得する

StackTrace を解析し (ここで概説されている方法を使用して: How to split a stacktrace line into namespace, class, method file and line number? )、args.Method.Name を解析結果と比較します。args.Method.Name が元のメソッド (StackTrace の解析で見つかった) と同じである場合は、それをログに記録する必要があることがわかります。それ以外の場合は無視します。

私のソリューションをより具体的にするためのコードを次に示します(引用された前の2つのソリューションに基づいています):

[Serializable]
public class ExceptionWrapper : OnExceptionAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
        var st = new StackTrace(args.Exception, true);
        var frame = st.GetFrame(0);
        var lineNumber = frame.GetFileLineNumber();
        var methodName = frame.GetMethod().Name;
        if(methodName.Equals(args.Method.Name))
        {
            string msg = string.Format("{0} had an error @ {1}: {2}\n{3}", 
                args.Method.Name, DateTime.Now, 
                args.Exception.Message, args.Exception.StackTrace);

            Trace.WriteLine(msg);
        }
    } 
}

(または、正直なところ、Gael が推奨するソリューションの 1 つを使用することもできます。)

于 2012-09-12T13:48:16.157 に答える
0

これが行われていることを確認できる1つの方法は、カスタム例外を定義し、それをアスペクトにスローすることです。次に、あなたの側面でも、ログインする前に例外をチェックし、カスタム例外でない場合はログに記録し、そうでない場合はログに記録せず、(再スローしますか?)。

サンプルコードは次のようになります。

[Serializable]
public class DatabaseExceptionWrapper : OnExceptionAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
      if(!(args.Exception is CustomException))
      {
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}", 
            args.Method.Name, DateTime.Now, 
            args.Exception.Message, args.Exception.StackTrace);

        Trace.WriteLine(msg);
      }

      throw new CustomException("There was a problem");
    } 
}

もちろん、その例外とすべてを定義する必要があります。:)

于 2012-04-25T21:35:35.397 に答える