Menu

Log handled exception?

2012-05-10
2014-02-23
  • Erik Funkenbusch

    Is there any way to log an exception and handle it? If I catch an exception, but don't want to leave it unhandled, i'd like to still log it in the Errors table. Can this be done easily?

     
  • Erik Funkenbusch

    FYI, I found a solution that works pretty well.

    try
    {
        throw new NotImplementedException();
    }
    catch (Exception e)
    {
        foreach (var filter in GlobalFilters.Filters)
        {
            if (filter.Instance is ErrorLogFilter)
            {
                var f = filter.Instance as ErrorLogFilter;
                f.OnException(new ExceptionContext(ControllerContext, e));
            }
        }
    }
    

    I actually took this one step further and created a .Log() extension method on Exception.

    public static class ExceptionExtensions
    {
        public static void Log(this Exception theException, ControllerContext theContext) 
        {
            foreach (var filter in GlobalFilters.Filters)
            {
                if (filter.Instance is ErrorLogFilter)
                {
                    var f = filter.Instance as ErrorLogFilter;
                    f.OnException(new ExceptionContext(theContext, theException));
                }
            }
        }
    }
    

    Then you just need to use it as such:

    try {
        throw new NotImplementedException();
    }
    catch (Exception e)
    {
        e.Log(ControllerContext);
    }
    
     

    Last edit: Erik Funkenbusch 2012-05-10
    • Steven Bey

      Steven Bey - 2012-05-11

      Thanks Erik. It's a nice solution, however, simply re-throwing the exception would notify ELFAR of the exception. I've written a blog post on the subject.

       

      Last edit: Steven Bey 2012-05-11
    • Wasiu

      Wasiu - 2013-04-26

      Very nice solution, but is it possible to log exceptions without having ControllerContext, for example in different console project ?
      I'd like to use sth like that:

      public static void Log(this Exception theException)
      {
      foreach (var filter in GlobalFilters.Filters)
      {
      if (filter.Instance is ErrorLogFilter)
      {
      var f = filter.Instance as ErrorLogFilter;
      f.OnException(new ExceptionContext(new ControllerContext(), theException));
      // f.OnException(new ExceptionContext(null, theException));

                      // var context = new ExceptionContext();
                      // context.Exception = theException;
                      // f.OnException(context);
                  }
              }
          }
      

      but without success. Everytime I got an error: "The method or operation is not implemented." or "Value cannot be null. Parameter name: controller" or "Object reference not set to an instance of an object."

      Can somebody help me ?

      Thanks in advance:
      Marcin

       
  • Erik Funkenbusch

    Rethrowing the exception will result in an unhandle exception propogating to the client, essentially resulting in a YSOD or 500 Internal Server Error. The whole point is to handle th exception, but log it so it can be investigated. I find this particularly useful with exceptions for external resources (Web requests, file access, etc..). There is no point in passing this on to the user if you can continue.

    Also, I read your blog and I think you should just use throw, rather than throw e. If you use throw e it will lose the stack trace.

     
    • Steven Bey

      Steven Bey - 2012-05-21

      I see your point. I've updated the blog post to include your comment but have left both solutions, so that people can us one or the other in the appropriate situation.

       
      • Jacek Gąsiorowski

        In MVC I'm not always handling exceptions in Controller. Sometimes I'm doing it in service layer etc. where ControllerContext is not accessible (if you will not pass it as a parameter). So I wrote additional extension method:

        public static void LogFromContext(this Exception theException)
            {
                foreach (var filter in GlobalFilters.Filters)
                {
                    if (filter.Instance is ErrorLogFilter)
                    {
                        var f = filter.Instance as ErrorLogFilter;
        
                        var fieldInfo = f.GetType().GetField("provider", BindingFlags.NonPublic | BindingFlags.Instance);
                        var provider = (IErrorLogProvider)fieldInfo.GetValue(f);
        
                        var context = HttpContext.Current;
        
                        var error = new ErrorLog(provider.Application, theException);
        
                        if (context != null)
                        {
                            error.User = context.User != null ? context.User.Identity.Name : string.Empty;
                            error.ServerVariables.Add(context.Request.ServerVariables);
                            error.QueryString.Add(context.Request.QueryString);
                            error.Form.Add(context.Request.Form);
                            error.Cookies.Add(context.Request.Cookies);
                        }
        
                        provider.Save(error);
                    }
                }
            }
        

        Hope that will going to help someone

         

Log in to post a comment.