質問

ASP.Net MVC 1.0アプリケーションで例外処理とエラー処理を組み合わせた簡単なソリューションを探しています。

ここでStackOverflowに投稿された質問を含む多くの記事を読みました。これらはすべて、さまざまな状況に対してさまざまなソリューションを提供します。私はまだ自分のニーズに合ったソリューションを思い付くことができません。

私の要件は次のとおりです。

  1. コントローラーで[HandleError]属性(または同等のもの)を使用して、アクションまたはビューのいずれかからスローされる可能性のあるすべての例外を処理できるようにします。これにより、どのアクションでも特に処理されなかったすべての例外を処理する必要があります(ポイント2で説明)。コントローラー内のすべてのアクションについて、エラーが発生した場合にユーザーをリダイレクトする必要があるビューを指定できるようにします。

  2. 特定のアクションの先頭に[HandleError]属性(または同等のもの)を指定して、特定の例外をキャッチし、例外に適切なビューにユーザーをリダイレクトできるようにしたい。他のすべての例外は、コントローラーの[HandleError]属性で処理する必要があります。

  3. 上記のどちらの場合でも、log4net(またはその他のロギングライブラリ)を使用して例外を記録します。

上記を達成するにはどうすればよいですか? OnExceptionメソッドをオーバーライドするベースコントローラーからすべてのコントローラーを継承し、ロギングを行うことについて読みました。ただし、これはユーザーを適切なビューにリダイレクトしたり、面倒にしたりすることに混乱します。

これを処理するためにIExceptionFilterを実装する独自のフィルターアクションを記述することを読みましたが、これは[HandleError]属性と競合します。

これまでのところ、私の考えは、最良の解決策は、HandleErrorAttributeを継承する独自の属性を記述することです。そのようにして、[HandleError]のすべての機能を取得し、独自のlog4netロギングを追加できます。解決策は次のとおりです。

    public class HandleErrorsAttribute: HandleErrorAttribute {

      private log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

      public override void OnException(ExceptionContext filterContext)
      {
          if (filterContext.Exception != null)
          {
            log.Error("Error in Controller", filterContext.Exception);
          }

          base.OnException(filterContext);
      }
   }

上記のコードは私の要件に対して機能しますか?そうでない場合、どのソリューションが要件を満たしますか?

役に立ちましたか?

解決

私はまだそこにあるすべてのさまざまなソリューション、および属性が互いに干渉する方法と少し混同していますが、このソリューションを使用しました:

public class LogErrorsAttribute: FilterAttribute, IExceptionFilter
{
    #region IExceptionFilter Members

    void IExceptionFilter.OnException(ExceptionContext filterContext)
    {
        if (filterContext != null && filterContext.Exception != null)
        {
            string controller = filterContext.RouteData.Values["controller"].ToString();
            string action = filterContext.RouteData.Values["action"].ToString();
            string loggerName = string.Format("{0}Controller.{1}", controller, action);

            log4net.LogManager.GetLogger(loggerName).Error(string.Empty, filterContext.Exception);
        }

    }

    #endregion
}

元の質問で説明したように、[HandleError]属性を引き続き使用し、各コントローラーを[LogErrors]属性で装飾します。

これは、エラーログを1か所に保持し、重複する例外が複数回ログに記録されないようにするために機能します([HandleError]を拡張して複数の場所で属性を使用すると発生します)。

非常に退屈で複雑になったり、[HandleError]の使用に影響を与えたりすることなく、例外ログとエラー処理を1つの属性またはクラスに結合することはできないと思います

ただし、[LogErrors]属性を使用して各コントローラーを1回だけ装飾し、コントローラーとアクションを[HandleError]を使用して、お互いに干渉することなく正確に装飾します。

更新:

使用方法の例を次に示します。

[LogErrors(Order = 0)]
[HandleError(Order = 99)]
public class ContactController : Controller
{
    public ActionResult Index()
    {
        return View(Views.Index);
    }

    public ActionResult Directions()
    {
        return View(Views.Directions);
    }


    public ActionResult ContactForm()
    {
        FormContactMessage formContactMessage = new FormContactMessage();

        return View(Views.ContactForm,formContactMessage);
    }

    [HandleError(ExceptionType = typeof(SmtpException), View = "MessageFailed", Order = 1)]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult ContactForm(FormContactMessage formContactMessage)
    {
        if (ModelState.IsValid)
        {
            if (formContactMessage.IsValid)
            {
                SmtpClient client = new SmtpClient();

                MailAddress recipientAddress = new MailAddress(Properties.Settings.Default.ContactFormRecipientEmailAddress);
                MailAddress senderAddress = new MailAddress(Properties.Settings.Default.ContactFormSenderEmailAddress);
                MailMessage mailMessage = formContactMessage.ToMailMessage(recipientAddress, senderAddress);

                client.Send(mailMessage);

                return View("MessageSent");
            }
            else
            {
                ModelState.AddRuleViolations(formContactMessage.GetRuleViolations());
            }
        }
        return View(Views.ContactForm, formContactMessage);
    }

    private static class Views
    {
        public static string Index { get { return "Index"; } }
        public static string Directions { get { return "Directions"; } }
        public static string ContactForm { get { return "ContactForm"; } }

    }
}

上記のコードでは、 ContactForm アクションオーバーロードのSmtpExceptionsは非常に具体的な方法で処理されます。ユーザーには、失敗した送信メッセージに固有のViewPageが表示されます。 MessageFailed" 。他のすべての例外は、[HandleError]のデフォルトの動作によって処理されます。また、エラーのログが最初に発生し、次にエラーの処理が続くことに注意してください。これは次のように示されます。

[LogErrors(Order = 0)]
[HandleError(Order = 99)]

更新:

これには別の解決策があり、非常に優れた説明があります。関連する問題をよりよく理解するために、これを一読することをお勧めします。

ASP.NET MVC HandleError属性、カスタムエラーページおよびロギングの例外 (以下の回答でリンクを提供してくれた下のScott Shepherdに感謝します)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top