有没有更好的方法来捕获异常?我好像在复制很多代码。基本上在每个控制器中我都有一个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语句中的行数?
答案 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中,可以通过使用过滤器来实现横切关注。过滤器是可以全局应用于控制器或方法的属性。它们在执行操作方法之前或之后运行。
您有多种类型的过滤器:
在您的情况下,您正在寻找异常过滤器。这些过滤器仅在操作方法中发生异常时运行。您可以全局应用过滤器,以便它可以自动运行任何控制器中的所有异常。您也可以专门在某些控制器或方法上使用它。
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背后的概念。