C# try-catch块中的代码重复
是否有更好的方法捕获异常?我好像在复制很多代码。基本上,在每个控制器中,我都有一个catch语句,它执行以下操作:C# try-catch块中的代码重复,c#,asp.net-mvc-4,exception-handling,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
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语句中的行数 您可以在这里使用扩展方法 在新类中创建扩展方法
public static class ExtensionMethods
{
public static void Log(this Exception obj)
{
// log your Exception here.
}
}
然后像这样使用它:
try
{
}
catch (Exception obj)
{
obj.Log();
}
也可以使用单例模式:
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) {}
...
}
及
编辑
有些人出于合理的理由不喜欢单身。我们可以使用一些DI代替单身:
class Controller
{
private ILogger logger;
public Controller(ILogger logger)
{
this.logger = logger;
}
}
并使用一些DI库将ILogger的一个实例注入控制器。您不需要在每个方法上都放置try/catch块。那是乏味和痛苦的!相反,您可以使用Global.asax的Application\u 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应用程序的三大静默性能杀手”正如我在本博客中所解释的那样,因为我非常不喜欢
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)
}
您试图做的事情被称为交叉关注点。您正在尝试记录代码中任何地方发生的任何错误 在ASP.NET中,可以通过使用过滤器来实现MVC横切关注点。过滤器是可以全局应用于控制器或方法的属性。它们在动作方法执行之前或之后运行 您有几种类型的过滤器:
- 授权筛选器,它们运行以检查是否允许用户访问资源
- 动作过滤器,它们在动作方法执行之前和之后运行
- 结果过滤器,这些过滤器可用于更改操作方法的结果(例如,向输出中添加一些额外的HTMl)
- 每当抛出异常时,都会运行异常筛选器
您可以找到如何实现自己的过滤器。我喜欢建议通用解决方案的答案,但是我想指出另一个适用于MVC的解决方案。 如果您有一个通用的控制器库(无论如何,这是IMO的最佳实践)。您可以简单地重写OneException方法:
public class MyControllerBase : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
DoSomeSmartStuffWithException(filterContext.Exception);
base.OnException(filterContext);
}
}
然后简单地从公共基继承普通控制器,而不是从控制器继承普通控制器
public class MyNormalController : MyControllerBase
{
...
如果您喜欢这个,您可以查看控制器类中其他方便的虚拟方法,它有很多。我在应用程序中使用了一个特殊的类,名为ExceptionHandler,在静态类中,我有一些方法来处理应用程序的异常。这使我有机会集中处理异常
public static class ExceptionHandler
{
public static void Handle(Exception ex, bool rethrow = false) {...}
....
}
在该方法中,您可以记录异常、重新显示异常、用另一种异常替换异常,等等
我用它来做这样的尝试
try
{
//Do something that might throw exceptions.
}
catch (exception ex)
{
ExceptionHandler.Handle(ex);
}
正如Wouter de Kort在他的回答中正确地指出的那样,这是一个跨领域的问题,因此我将该类放在我的应用程序层中,并将其作为服务使用。如果将类定义为接口,则可以在不同的场景中使用不同的实现 在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已经解释了这个概念。查看“ASP.NET MVC4中的面向方面编程”@ AHMMEKRAIEM,或者只需降到C++,并使用宏来表示一切。AOP是一种黑客-如果我可以的话。@Gusdor“AOP是个黑客。”这是你的意见。但尽管如此,AOP并不是这里的最佳解决方案,@gusdor Ahmed提到的定制操作过滤器不需要IL屠宰。我知道AOP在.NET中还没有得到很好的支持,但属性是一种实现横切关注点的方法,而无需手动向每个关注点添加代码method@Gusdor-我明白了。你应该学会更隐晦地掩饰你的讽刺:请不要使用单身汉。SUNITLON是一种反模式,它使测试变得困难、困难、困难,并且应该避免。@ DavidArno,我在C++代码中使用“SuntLon”类。您对“Factory”类或某些管理器类(例如“ThreadManager”或“ThreadPool”)而不是Singleton有何建议?@Mohammadderb Deendency injection,如您所述。由于未知的副作用,单例使您的代码更难阅读(代码在您未传入的某些全局可用对象上执行方法)。DI清楚地说明了你的代码依赖于什么。@DavidArno:小心刻板印象!静态扩展方法(您投票赞成)与单例中包含的日志记录方法一样难以测试。@DavidArno:我恐怕不明白您的意思。将
publicstaticsomemethoda(){…}
与publicstaticmyclass实例=newmyclass()进行比较;私有MyClass(){}公共SomeMethodB(){…}
。SomeMethodA
和SomeMethodB
都同样难以测试!唯一的区别是第一个是使用MyClass.SomeMethodA()
执行的,第二个是使用MyClass.Instance.SomeMethodB()
执行的。如此简单,如此聪明,
public class MvcApplication : HttpApplication
{
protected override void OnApplicationStarted()
{
// ...
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// ...
}
}