Подтвердить что ты не робот

ASP.Net MVC Exception Logging в сочетании с обработкой ошибок

Я ищу простое решение для ведения журнала исключений в сочетании с обработкой ошибок в приложении ASP.Net MVC 1.0.

Я прочитал много статей, в том числе вопросы, размещенные здесь в StackOverflow, которые предоставляют различные решения для разных ситуаций. Я по-прежнему не в состоянии найти решение, соответствующее моим потребностям.

Вот мои требования:

  • Чтобы иметь возможность использовать атрибут [HandleError] (или что-то подобное) на моем контроллере, обрабатывать все исключения, которые могут быть выбраны из любого из Actions или Views. Это должно обрабатывать все исключения, которые не были обработаны специально для любого из действий (как описано в пункте 2). Я хотел бы иметь возможность указать, какой вид пользователя должен быть перенаправлен пользователю в случаях ошибок, для всех действий в контроллере.

  • Я хочу, чтобы указать атрибут [HandleError] (или что-то подобное) в верхней части определенных действий, чтобы поймать определенные исключения и перенаправить пользователей в представление, соответствующее исключению. Все остальные исключения по-прежнему должны обрабатываться атрибутом [HandleError] на контроллере.

  • В обоих случаях выше, я хочу, чтобы исключения регистрировались с использованием 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);
      }
   }

Будет ли приведенный выше код работать для моих требований? Если нет, какое решение удовлетворяет моим требованиям?

4b9b3361

Ответ 1

Я все еще немного запутался со всеми различными решениями там и как атрибуты могут мешать друг другу, но я пошел с этим решением:

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].

Это работает для меня, так как он ведет журнал регистрации ошибок в одном месте и не вызывает многократные записи повторяющихся исключений (что произойдет, если я продлю [HandleError] и использую атрибут в нескольких местах).

Я не думаю, что можно будет объединить как журнал регистрации исключений, так и обработку ошибок в один атрибут или класс, не становясь очень утомительным и сложным, или влияя на использование [HandleError]

Но это работает для меня, так как я украшаю каждый контроллер только один раз, с атрибутом [LogErrors] и украшаю контроллеры и действия с помощью [HandleError] точно так, как я хочу, без их вмешательства друг в друга.

Update:

Вот пример того, как я его использую:

[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"; } }

    }
}

В приведенном выше коде SmtpExceptions в перегрузке действий ContactForm обрабатываются очень определенным образом - пользователю предоставляется конкретная функция ViewPage для неудавшихся отправленных сообщений, в этом случае она называется "MessageFailed". Все остальные исключения обрабатываются поведением по умолчанию [HandleError]. Также обратите внимание, что сначала регистрируется ошибка, а затем обработка ошибок. Об этом говорит следующее:

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

Update:

Существует альтернативное решение этого, с очень хорошим объяснением. Я рекомендую прочитать его, чтобы лучше понять связанные с этим проблемы.

Атрибут ASP.NET MVC HandleError, пользовательские страницы ошибок и исключения журналов (Спасибо Скотту Шеферду ниже, кто предоставил ссылку в ответе ниже).