在上一篇中"异常处理--Exception(一)"中,跟你们简单介绍了一下Exception,也使你们充分的了解了Exception管理在一个项目中的重要性,那如何在咱们的项目中处理异常呢?由于我从事的是Web开发,因此我只跟你们讨论Web的解决方案,Win的解决方式,还但愿同你们一块儿探讨。html
上一章中咱们了解了异常发生的缘由,同时也说了不存在没有bug的程序,任何网站都会遇到各类各样的问题,不管是大网站仍是小网站都会存在,但大公司和小公司对待异常的态度全然不一样,一个是主动出击,一个是守株待兔,咱们是好的开发者,咱们不能坐以待毙,咱们必须主动出击。好了,废话少说,切入主题。数据库
如今网站通常都采用多层开发,多层开发的时候,咱们应该在哪里处理异常、在抛出异常呢?微软的意见是类库的开发人员尽可能不要处理异常,类库的编写应该按照正常的逻辑去编写,固然也有例外,注意事项能够参见"设计异常解决方案的几点注意事项",好的,按照规范,咱们应该尽可能在高层进行捕捉和处理,那咱们该怎么捕捉,捕捉后怎么处理,捕捉哪些异常呢?虽然微软提供了不少系统异常,可是这些异常只是负责抛出相关的信息,并无为记录下来,或者出现高级异常的时候,及时通知咱们,这样的作法仍是守株待兔,咱们仍是应该主动的对其进行处理。好在微软让咱们能够自由的建立自定义的Exception,最好是设定一个自定义Exception基类,让你的其余自定义Exception都继承这个类,以便从此更好的扩展。抛出异常实际上是性能消耗很大的操做,可是Richer教父说过,抛出异常的性能和你程序的稳定性相比,就变得很是眇小了。因此咱们仍是偏向于稳定性。由于处理异常的性能消耗,只是在异常发生时才产生,因此性能方面的问题,咱们能够忽略了。(或许这话比较拗口,但相比系统的性能,我更趋向于系统的稳定)安全
如何建立一个自定义的Exception?post
不得不说微软考虑的太周到了,要建立一个自定义的Exception是很是简单的。打开VS,建立一个项目,而后添加一个类,在namespace范围内,输入Exception,而后2下Tab,VS就自定帮您建立一个自定义的Exception了。Exception的相关属性和方法,能够参见MSDN。不过自动建立的Exception都是继承System.Exception的,按照微软当初的设想,自定义的异常应该继承System.ApplicationException (好笑的是,微软本身都没有遵照这个约定)。咱们设定这个做为咱们的Exception基类MyBaseException。性能
代码片段:网站
[global::System.Serializable] ui
public class MyBaseException : ApplicationException spa
{ 设计
public MyBaseException() { } 日志
public MyBaseException(string message) : base(message) { }
public MyBaseException(string message, Exception inner) : base(message, inner) { }
protected MyBaseException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
这就是一个标准的自定义Exception了,至于其它的自定义Exception,应该根据你的项目来进行相关的定义。
在进行其余定义以前,咱们先来想一想,咱们捕捉这些Exception以后咱们须要作些什么?咱们须要知道异常发生的各类信息,因此咱们须要Log。Log能方便的让咱们查阅发生的异常及Log的异常信息。Log有不少方式,大概的有如下几种:
文本记录
数据库记录
系统事件记录(Trace)
第三方组件(Log4Net)
这几种方式各有利弊,能够根据项目的需求进行选择,固然你也能够几种方式合用,好比咱们默认的是文本记录方式,可是在建立Log时发生了System.IOException时,咱们就必须选择其余的方式进行Log。
Log方式 |
便捷性 |
查阅性 |
安全性 |
结合性 |
文本记录 |
方便 |
通常 |
低 |
高 |
数据库记录 |
通常 |
方便 |
通常 |
高 |
系统事件记录 |
复杂 |
复杂 |
高 |
通常 |
第三方组件 |
复杂 |
通常 |
通常 |
低 |
我列举了几种方式的利弊,你们能够有条件的选择。若是你的项目中已经使用第三方组件记录方式,那我建议您使用它。在我后面的解决方案中,我会利用前2种比较常见的方式相结合。
Log的目的是为咱们开发者提供发生异常的时间、地点、人物、缘由,因此咱们必须尽量的详细地记录,根据一个Exception获取信息的方法:
Data |
Source |
Dates and Times |
DateTime.Now |
Source of Exception |
Exception.Source |
Type of Exception |
Object.GetType |
Exception Message |
Exception.Message |
Current Method |
Reflection.MethodInfo.GetCurrentMethod |
Machine Name |
Environment.MachineName or Dns.GetHostName |
CurrentIP |
Dns.GetHostByName("host").AddressList[0].Address |
Call Stack |
Exception.StackTrace or Environment.StackTrace |
OS Information |
Environment.OSVersion |
Applcation Domain |
AppDomain.FriendlyName |
Current Assembly |
Reflection.Assembly.GetExecutingAssembly |
Root Error Cause |
Exception.GetBaseException |
Chained Exception |
Exception.InnerException |
Assembly Version |
Included in AssemblyName.FullName |
Thread ID |
AppDomain.GetCurrentThreadId |
Thread User |
Threading.Thread.CurrentPrincipal |
咱们能够根据上面的表格,构建咱们本身所须要的Log信息。为了便捷的管理,咱们应该采用同一格式,进行Log。这里贴一个我写的信息格式,以供参考:
public static class ExceptionLogFormatHelper
{
public static string ExceptionLogFormatter(Exception ex)
{
StringBuilder sbLog = new StringBuilder("\r\n------------------------------------\r\n");
Exception ochainException = ex;
var currentExceptionIndex = 1;
while (ochainException != null)
{
sbLog.Append("\r\nException " + currentExceptionIndex + " )")
.Append("\r\nException Type:" + ochainException.GetType().FullName)
.Append("\r\nException Source:" + ochainException.Source)
.Append("\r\nException Message:" + ochainException.Message)
.Append("\r\nException Date:" + DateTime.Now)
.Append("\r\nEnvironment Stack:" + System.Environment.StackTrace);
ochainException = ochainException.InnerException;
currentExceptionIndex++;
}
sbLog.Append("\r\n------------------------------------\r\n");
return sbLog.ToString();
}
}
你也能够根据你本身想要的信息构建这么一个方法。
这一篇废话多了点,不过仍是有必要了解下。还介绍了自定义异常的建立,日志方式的对比,在下一篇,我将介绍通知、异常处理流程和定义本身的一个MyBaseException。