25

例外をキャッチするより良い方法はありますか? 多くのコードを複製しているようです。基本的にすべてのコントローラーに、これを行う catch ステートメントがあります。

try
{
     Do  something that might throw exceptions.
}
catch (exception ex)
{
     Open database connection
     Save exception details.
     If connection cannot be made to the database save exception in a text file.
}

コントローラーが 4 つあり、コントローラーごとに約 5 ~ 6 個のアクション メソッドがあり、多くのコードが重複しています。上記の try catch ステートメントの行数を減らすにはどうすればよいですか?

4

8 に答える 8

42

ここで拡張メソッドを利用できます。

新しいクラスに拡張メソッドを作成します。

public static class ExtensionMethods
{
    public static void Log(this Exception obj)
    {
        // log your Exception here.
    }
}

そして、次のように使用します。

try
{
}
catch (Exception obj)
{
    obj.Log();
}
于 2013-10-16T07:53:38.527 に答える
13

すべてのメソッドに try/catch ブロックを配置する必要はありません。それは退屈で痛いです!代わりに、Global.asaxのApplication_Errorイベントを使用して、例外をログに記録できます。以下のコードは、Web アプリケーションで発生する例外をキャッチするために使用できるサンプル実装です。

protected void Application_Error(object sender, EventArgs e)
{
    var error = Server.GetLastError();
    if (!string.IsNullOrWhiteSpace(error.Message))
    {
        //do whatever you want if exception occurs
        Context.ClearError();
    }
}

このブログhttp://mvoloで説明されているように、「処理された例外」、特にほとんどのメソッドに try/catch ブロックを配置しようとすることは、「IIS / ASP.NET アプリのサイレント パフォーマンス キラーのトップ 3」の 1 つであることも強調したいと思います。 .com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/

于 2013-10-16T08:28:02.470 に答える
11

あなたがやろうとしていることは、横断的関心事と呼ばれます。コードのどこかで発生したエラーをログに記録しようとしています。

ASP.NET MVC では、フィルターを使用して分野横断的な懸念を実現できます。フィルターは、コントローラーまたはメソッドにグローバルに適用できる属性です。これらは、アクション メソッドの実行前または実行後に実行されます。

いくつかのタイプのフィルターがあります。

  • 承認フィルター。ユーザーがリソースへのアクセスを許可されているかどうかを確認するために実行されます。
  • アクション フィルター。これらは、アクション メソッドの実行の前後に実行されます。
  • 結果フィルター。アクション メソッドの結果を変更するために使用できます (たとえば、出力に HTMl を追加するなど)。
  • 例外フィルターは、例外がスローされるたびに実行されます。

あなたの場合、例外フィルターを探しています。これらのフィルターは、アクション メソッドで例外が発生した場合にのみ実行されます。フィルターをグローバルに適用して、任意のコントローラーのすべての例外に対して自動的に実行されるようにすることができます。特定のコントローラーまたはメソッドで具体的に使用することもできます。

この MSDN ドキュメントでは、独自のフィルターを実装する方法を見つけることができます。

于 2013-10-16T08:54:22.860 に答える
4

アプリケーションでExceptionHandlerと呼ばれる特別なクラスを使用しました。静的なクラスには、アプリケーションの例外を処理するメソッドがいくつかあります。これにより、例外処理を一元化する機会が得られます。

public static class ExceptionHandler
{
    public static void Handle(Exception ex, bool rethrow = false) {...}
    ....   
}

メソッドでは、例外をログに記録したり、再スローしたり、別の種類の例外に置き換えたりすることができます。

このようなtry/catchで使用します

try
{
    //Do something that might throw exceptions.
}
catch (exception ex)
{
    ExceptionHandler.Handle(ex);
}

Wouter de Kortが彼の回答で正しく述べているように、これは分野横断的な懸念であるため、クラスをアプリケーション層に配置し、サービスとして使用しました。クラスをインターフェイスとして定義すると、さまざまなシナリオでさまざまな実装を行うことができます。

于 2013-10-16T13:31:23.760 に答える
4

try個人的には/ブロックが大嫌いなので、再利用可能な/ブロックでアクションをラップするメソッドを含むクラスcatchを使用しています。元:static Trytrycatch

public static class Try {
   bool TryAction(Action pAction) {
      try {
         pAction();
         return true;
      } catch (Exception exception) {
         PostException(exception);
         return false;
      }
   }

   bool TryQuietly(Action pAction) {
      try {
         pAction();
         return true;
      } catch (Exception exception) {
         PostExceptionQuietly(exception);
         return false;
      }
   }

   bool TrySilently(Action pAction) {
      try {
         pAction();
         return true;
      } catch { return false; }
   }

   // etc... (lots of possibilities depending on your needs)
}
于 2013-10-16T08:43:15.747 に答える
3

また、シングルトン パターンを使用することもできます。

sealed class Logger
{
    public static readonly Logger Instance = new Logger();

    some overloaded methods to log difference type of objects like exceptions
    public void Log(Exception ex) {}
    ...
}

Try
{
}
Catch(Exception ex)
{
    Logger.Instance.Log(ex);
}

編集 一部の人々は、合理的な理由でシングルトンが好きではありません.シングルトンの代わりに、いくつかのDIを使用できます。

class Controller
{
    private ILogger logger;

    public Controller(ILogger logger)
    {
        this.logger = logger;
    }
}

ILogger の 1 つのインスタンスをコントローラーに挿入する DI ライブラリを使用します。

于 2013-10-16T08:04:23.560 に答える
3

一般的な解決策を示唆する回答が好きですが、MVC で機能する別の回答を指摘したいと思います。共通のコントローラー ベースがある場合 (いずれにせよ、それは IMO のベスト プラクティスです)。OnException メソッドをオーバーライドするだけです。

public class MyControllerBase : Controller
{
    protected override void OnException(ExceptionContext filterContext)
    {
        DoSomeSmartStuffWithException(filterContext.Exception);
        base.OnException(filterContext);
    }
}

次に、コントローラーの代わりに共通ベースから通常のコントローラーを継承するだけです

public class MyNormalController : MyControllerBase 
{
    ...

これが気に入ったら、他の便利な仮想メソッドの Controller クラスをチェックアウトできます。多くのメソッドがあります。

于 2013-10-16T10:32:17.570 に答える
1

ASP .NET MVC では、独自のものを実装HandleErrorAttributeして、すべてのコントローラーで発生するすべての例外をキャッチできます。

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
      var ex = filterContext.Exception;

      //     Open database connection
      //     Save exception details.
      //     If connection cannot be made to the database save exception in a text file.
    }
 }

次に、このフィルターを登録します。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
       filters.Add(new CustomHandleErrorAttribute());
    }
 }

もちろん、アプリケーションの起動時に register メソッドを呼び出します。

public class MvcApplication : HttpApplication
{
    protected override void OnApplicationStarted()
    {
       // ...
       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
       // ...
    }
}

Wouter de Kort は、彼の回答でこの背後にある概念を既に説明しています。

于 2013-10-16T18:33:13.080 に答える