try catch块中的代码重复

时间:2013-10-16 07:52:00

标签: c# asp.net-mvc-4 exception-handling

有没有更好的方法来捕获异常?我好像在复制很多代码。基本上在每个控制器中我都有一个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语句中的行数?

8 个答案:

答案 0 :(得分:40)

您可以在此处使用扩展方法。

在新班级中创建扩展方法。

public static class ExtensionMethods
{
    public static void Log(this Exception obj)
    {
        // log your Exception here.
    }
}

并使用它:

try
{
}
catch (Exception obj)
{
    obj.Log();
}

答案 1 :(得分: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的“前3个静默性能杀手”之一。 NET应用“,如本博客http://mvolo.com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/

中所述

答案 2 :(得分:11)

您要做的事情被称为跨领域的关注点。您正在尝试记录代码中任何位置发生的任何错误。

在ASP.NET MVC中,可以通过使用过滤器来实现横切关注。过滤器是可以全局应用于控制器或方法的属性。它们在执行操作方法之前或之后运行。

您有多种类型的过滤器:

  • 授权过滤器,它们运行以检查是否允许用户访问资源。
  • 动作过滤器,它们在动作方法执行之前和之后运行。
  • 结果过滤器,这些过滤器可用于更改操作方法的结果(例如,向输出添加一些额外的HTMl)
  • 每当抛出异常时都会运行异常过滤器。

在您的情况下,您正在寻找异常过滤器。这些过滤器仅在操作方法中发生异常时运行。您可以全局应用过滤器,以便它可以自动运行任何控制器中的所有异常。您也可以专门在某些控制器或方法上使用它。

Here in the MSDN documentation您可以找到如何实施自己的过滤器。

答案 3 :(得分: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)
}

答案 4 :(得分: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在他的回答中正确指出的那样,这是一个贯穿各领域的问题,所以我把这个类放在我的应用层中,并将其用作服务。如果您将类定义为接口,则可以在不同的方案中对其进行不同的实现。

答案 5 :(得分:3)

您也可以使用Singleton模式:

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

修改 有些人不喜欢Singleton的合理理由。除了单身人士,我们可以使用一些DI:

class Controller
{
    private ILogger logger;

    public Controller(ILogger logger)
    {
        this.logger = logger;
    }
}

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

答案 6 :(得分: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类以获取其他方便的虚拟方法,它有很多。

答案 7 :(得分: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已经解释了这个in his answer背后的概念。