个人觉得EnterLib的EHAB(Exception Handling Application Block)是一个不错的异常处理框架,借助于EHAB,我们可以配置的方式来自定义异常处理策略,从而带来最大的灵活性和可维护性。但是,在我看来,EHAB有一个最大的局限,把就是异常处理策略的粒度过大——只能提供基于异常类型级别。本篇文章通过一个自定义ExceptionHandler很好地解决了这个问题。
EnterLib的异常处理策略基本上可以通过这样的的公式来表示:Exception Policy = Exception Type + Exception Handlers + Post Handling Action,它表达的意思是:“对于某种类型的异常,应该采用哪些Exception Handler去处理,而被处理后的异常还需要采用怎样的后续操作(将异常吃掉、或者是重新抛出)”。
也就是说,抛出类型的异常类型决定了最终采取的处理策略,这在大部分情况下是可以接受的。但是在很多场景中,不同情况下也可以抛出相同类型的异常,我们期望的行为是:尽管异常类型一样,我们也可以根据具体抛出的异常定义不同的异常处理策略。
一个最为典型的场景就是基于数据库的数据存取,如果你采用的SQL Server,抛出的异常永远只有一种:SqlException。如果完全按照EnterLib EHAB的做法,在任何情况下抛出的SqlException对应的处理方式都是一样的。但是抛出SqlException的情况非常多,比如Server连接断开、认证失败、数据库对象不存在、违反一致性约束等等,如果异常处理框架能够根据最终抛出的异常的具体属性,“智能”地应用相应的策略去处理,这才是我们乐于看到的。
二、一个特殊的ExceptionHandler——FilterableHandler
为了解决这个问题,我创建了一个特殊的Exception Handler,我将它起名为FilterableHandler。说它特别,是因为FilterableHandler并不从事具体的异常处理操作(比如异常封装、替换、日志等),而是为某个具体的异常类型重新定义了异常处理策略。
实际上,我在很早之前就定义了一个相似的FilterableHandler,有兴趣的话可以参考《创建一个自定义Exception Handler改变ELAB的异常处理机制》。由于在最新的EnterLib中,底层的实现机制发生了根本性的改变,这个ExceptionHandler已经不能在使用。所以我对其进行的了修正,同时根据可扩展性进行重新设计。
之所以称这个ExceptionHandler为FilterableHandler,是在于它具有对抛出的异常具有“筛选”的功能。说得具体点,FilterableHandler将抛出的异常对象,传入一组具有筛选功能的ExceptionHandler列表,我个人将这个列表命名为FiterableExceptionHandlerPipeline。FiterableExceptionHandlerPipeline对象包含一个筛选器和一组ExceptionHandler,如果传入的异常通过了筛选器的筛选,该异常最终被分发到相应的ExceptionHandler列表中进行处理。FiterableExceptionHandlerPipeline大概的定义如下:
2: {
private set; }
private set; }
5:
public FilterableHandlerPipeline(IFilter filter, IEnumerable<IExceptionHandler> exceptionHandlers)
7: {
);
);
this.Filter = filter;
this.ExceptionHandlers = exceptionHandlers;
12: }
13: }