2009-06-23 2 views
22

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

Я читал много статей, включая вопросы, размещенные здесь в 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); 
     } 
    } 

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

ответ

24

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

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] и использую атрибут в нескольких местах).

Я не думаю, что это будет возможно сочетать оба Logging Exception и обработка ошибок в один atrribute или класс, без него становится очень утомительным и сложным, или влияющих на использование [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:

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

ASP.NET MVC HandleError Attribute, Custom Error Pages and Logging Exceptions (Спасибо Скотту Шеферду ниже, кто предоставил ссылку в ответе ниже).

+0

Ницца, спасибо большое, я буду использовать это. – Kezzer

+3

Я подозреваю, что этот код имеет ошибку, в которой он принимает значение null, не возвращается для RouteData.Values ​​["action"] - вызов .ToString() может привести к тому, что ваш обработчик ошибок выкинет исключение NullReferenceException. Нет ничего более неприятного, чем обработчик ошибок, бросающий ошибку. –

Смежные вопросы