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();
    }
}

我还想强调,“处理的异常” ,尤其是尝试在大多数方法上放置 try/catch 块是“IIS / ASP.NET 应用程序的三大无声性能杀手”之一,如本博客http://mvolo 中所述.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

就个人而言,由于我非常不喜欢try/catch块,所以我使用一个static Try包含将动作包装在可重用try/catch块中的方法的类。前任:

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 回答
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 回答
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;
    }
}

并使用一些 DI 库,将 ILogger 的一个实例注入您的控制器。

于 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);
    }
}

然后只需从您的公共基础而不是 Controller 继承您的普通控制器

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 回答