Enterprise Library Step By Step系列(十二):异常处理应用程序块——进阶篇

简介:
一.把异常信息 Logging 到数据库
在日志和监测应用程序块中,有朋友提意见说希望能够把异常信息 Logging 到数据库中,在这里介绍一下具体的实现方法。
1.创建相关的数据库环境:
我们可以用日志和监测应用程序块自带的 SQL 语句来创建相关的数据库环境:
创建数据库:
None.gif CREATE   DATABASE   [ Logging ]    ON  (NAME  =  N ' Logging ' , FILENAME  =  N ' C:\Program Files\Microsoft SQL Server\MSSQL\data\Logging.mdf '  , SIZE  =   1 , FILEGROWTH  =   10 % LOG   ON  (NAME  =  N ' Logging_log ' , FILENAME  =  N ' C:\Program Files\Microsoft SQL Server\MSSQL\data\Logging_log.LDF '  , FILEGROWTH  =   10 % )
创建表:
None.gif CREATE   TABLE   [ dbo ] . [ Log ]  (
None.gif    
[ LogID ]   [ int ]   IDENTITY  ( 1 1 NOT   NULL  ,
None.gif    
[ EventID ]   [ int ]   NULL  ,
None.gif    
[ Category ]   [ nvarchar ]  ( 64 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ Priority ]   [ int ]   NOT   NULL  ,
None.gif    
[ Severity ]   [ nvarchar ]  ( 32 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ Title ]   [ nvarchar ]  ( 256 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ Timestamp ]   [ datetime ]   NOT   NULL  ,
None.gif    
[ MachineName ]   [ nvarchar ]  ( 32 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ AppDomainName ]   [ nvarchar ]  ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ ProcessID ]   [ nvarchar ]  ( 256 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ ProcessName ]   [ nvarchar ]  ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NOT   NULL  ,
None.gif    
[ ThreadName ]   [ nvarchar ]  ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NULL  ,
None.gif    
[ Win32ThreadId ]   [ nvarchar ]  ( 128 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NULL  ,
None.gif    
[ Message ]   [ nvarchar ]  ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS  NULL  ,
None.gif    
[ FormattedMessage ]   [ ntext ]  COLLATE SQL_Latin1_General_CP1_CI_AS  NULL  
None.gif
ON   [ PRIMARY ]  TEXTIMAGE_ON  [ PRIMARY ]
None.gif
GO
None.gif
创建存储过程:
 1 None.gif CREATE   PROCEDURE  WriteLog
 2 None.gif(
 3 None.gif     @EventID   int
 4 None.gif     @Category   nvarchar ( 64 ),
 5 None.gif     @Priority   int
 6 None.gif     @Severity   nvarchar ( 32 ), 
 7 None.gif     @Title   nvarchar ( 256 ), 
 8 None.gif     @Timestamp   datetime ,
 9 None.gif     @MachineName   nvarchar ( 32 ), 
10 None.gif     @AppDomainName   nvarchar ( 2048 ),
11 None.gif     @ProcessID   nvarchar ( 256 ),
12 None.gif     @ProcessName   nvarchar ( 2048 ),
13 None.gif     @ThreadName   nvarchar ( 2048 ),
14 None.gif     @Win32ThreadId   nvarchar ( 128 ),
15 None.gif     @Message   nvarchar ( 2048 ),
16 None.gif     @FormattedMessage   ntext
17 None.gif)
18 None.gif AS  
19 None.gif
20 None.gif     INSERT   INTO   [ Log ]  (
21 None.gif        EventID,
22 None.gif        Category,
23 None.gif        Priority,
24 None.gif        Severity,
25 None.gif        Title,
26 None.gif         [ Timestamp ] ,
27 None.gif        MachineName,
28 None.gif        AppDomainName,
29 None.gif        ProcessID,
30 None.gif        ProcessName,
31 None.gif        ThreadName,
32 None.gif        Win32ThreadId,
33 None.gif        Message,
34 None.gif        FormattedMessage
35 None.gif    )
36 None.gif     VALUES  (
37 None.gif         @EventID
38 None.gif         @Category
39 None.gif         @Priority
40 None.gif         @Severity
41 None.gif         @Title
42 None.gif         @Timestamp ,
43 None.gif         @MachineName
44 None.gif         @AppDomainName ,
45 None.gif         @ProcessID ,
46 None.gif         @ProcessName ,
47 None.gif         @ThreadName ,
48 None.gif         @Win32ThreadId ,
49 None.gif         @Message ,
50 None.gif         @FormattedMessage )
51 None.gif GO
SQL 语句默认的路径为 C:\Program Files\Microsoft Enterprise Library\src\Logging\Sinks\Database\Scripts ,直接运行 CreateLoggingDatabase.cmd 即可。
2.运行配置工具,我们创建一个日志和监测应用程序块,并建一个Database Sink,具体的配置方法在日志和监测应用程序块中讲过了,这里就不重复了,我们看一下它的配置:
 
注意设置 StoredProcName WriteLog ,就是我们刚才创建的存储过程。
3.同时再创建一个Category,起名为DataException,并设置它的SinkDatabase Sink
4.设置Logging HandlerLogCategory为我们刚才创建的DataException,其他的参数暂时默认。
 
5.至此配置完成,在程序中我们不需要做任何改动(这就是企业库的配置驱动的思想精妙之处^_^)。
 1 ExpandedBlockStart.gif /// <summary>
 2InBlock.gif        /// 日志策略
 3InBlock.gif        /// </summary>
 4InBlock.gif        /// <param name="sender"></param>
 5ExpandedBlockEnd.gif        /// <param name="e"></param>

 6 None.gif          private   void  btn_Log_Click( object  sender, System.EventArgs e)
 7 ExpandedBlockStart.gif         {
 8InBlock.gif            try
 9ExpandedSubBlockStart.gif            {
10InBlock.gif                Exception ex = new Exception();
11InBlock.gif                throw ex;
12ExpandedSubBlockEnd.gif            }

13InBlock.gif            catch(Exception ex)
14ExpandedSubBlockStart.gif            {
15InBlock.gif                bool Flag = ExceptionPolicy.HandleException(ex,"Log Policy");
16InBlock.gif
17InBlock.gif                if(Flag)
18ExpandedSubBlockStart.gif                {
19InBlock.gif                    throw;
20ExpandedSubBlockEnd.gif                }

21ExpandedSubBlockEnd.gif            }

22ExpandedBlockEnd.gif        }

补充一点:在项目中要添加对Microsoft.Practices.EnterpriseLibrary.Logging.Sinks.Database.dll的引用

二.异常的传播机制
异常的传播机制有以下几种:
l        异常自动传播
l        在同一层内部,捕获或者再抛出原有异常
l        捕获,包装和抛出包装后的异常
我们不推荐直接抛出原有异常,因为恶意的用户能够从系统诊断信息中得知应用的详细情况,并从中查找应用的弱点。异常应用程序块提供了 一旦配置的 Handler 执行后,就产生对应的 post-handling 动作,该动作有如下选项:
None    没有重抛异常的动作。
NotifyRethrow    告诉调用程序: Policy 推荐应该重抛异常。
ThrowNewException    在所有的 Handler 执行后,向调用程序抛出最终异常(并不一定是原始的异常)。

三.异常的格式化
可以格式化任何 System.Exception 类型的异常
能够用来记录或者显示异常的详细信息
字符型格式化器—— TextExceptionFormatter :创建在一个屏幕上,日志中或以其他形式表现的,可以表现异常信息的详细记录
XML 格式化器—— XMLExceptionFormatter :针对一个异常,创建一个用 XML 表现形式表现记录,每一个异常的属性,均可以被存储为 XML 元素。
看一下在 Enterprise Library Quick Start 中提供的自定义的 ExceptionFormatter ,实现了 TextExceptionFormatter 类:
 1 ExpandedBlockStart.gif /// <summary>
 2InBlock.gif    /// Summary description for AppTextExceptionFormatter.
 3ExpandedBlockEnd.gif    /// </summary>    

 4 None.gif      public   class  AppTextExceptionFormatter : TextExceptionFormatter
 5 ExpandedBlockStart.gif     {
 6InBlock.gif        public AppTextExceptionFormatter(TextWriter writer, Exception exception)
 7InBlock.gif            : base (writer, exception) 
 8ExpandedSubBlockStart.gif            {
 9ExpandedSubBlockEnd.gif            }

10InBlock.gif        
11InBlock.gif        protected override void WriteDescription() 
12ExpandedSubBlockStart.gif        {
13InBlock.gif            // An exception of type {0} occurred and was caught.
14InBlock.gif            string line = String.Format("An exception of type {0} occurred and was caught."base.Exception.GetType().FullName);
15InBlock.gif            this.Writer.WriteLine(line);
16ExpandedSubBlockEnd.gif        }

17InBlock.gif
18InBlock.gif        protected override void WriteExceptionType(Type exceptionType) 
19ExpandedSubBlockStart.gif        {
20InBlock.gif            base.Indent();
21InBlock.gif            base.Writer.WriteLine("Type : {0}", exceptionType.FullName);
22ExpandedSubBlockEnd.gif        }

23InBlock.gif
24InBlock.gif        public override void Format() 
25ExpandedSubBlockStart.gif        {
26InBlock.gif            //this.Writer.WriteLine("Message : {0}", message);
27InBlock.gif            this.WriteDescription();
28InBlock.gif            //this.WriteExceptionType(base.Exception.GetType());
29InBlock.gif            base.WriteMessage(base.Exception.Message);
30ExpandedSubBlockEnd.gif        }

31InBlock.gif
32ExpandedBlockEnd.gif    }
四.创建自定义的异常处理器
异常处理应用程序块允许您包装并使用您自己的例外业务处理流程,例如在时间记录系统中填写一个事件,利用业务规范进行包装和替代,利用另外的记录系统进行记录(比较常用的有 Log4net ,前段时间 深渊野鱼 介绍的,还没用过 ^_^ ),这种灵活的可配置性,将允许您在不同的异常类型及其策略中灵活的配置。
可以通过实现 ExceptionHandler 抽象类,来创建定制的 Handler
1 None.gif public   abstract   class  ExceptionHandler : ConfigurationProvider, IExceptionHandler
该抽象类继承 ConfigurationProvider 类,并实现 IExceptionHandler 接口。 ConfigurationProvider 抽象类实现了 IConfigurationProvider 接口,用来读取配置数据。
1 None.gif public   abstract   class  ConfigurationProvider : IConfigurationProvider
使用支持序列化的数据类型作为配置参数,还有要注意数据类型的简单,避免“ Exception Handling Exceptions
看一下在 Enterprise Library Quick Start 中提供了定制 Handler 的实现:
 1 ExpandedBlockStart.gif /// <summary>
 2InBlock.gif  /// Summary description for GlobalPolicyExceptionHandler.
 3ExpandedBlockEnd.gif  /// </summary>

 4 None.gif    public   class  AppMessageExceptionHandler : ExceptionHandler
 5 ExpandedBlockStart.gif   {
 6InBlock.gif    public AppMessageExceptionHandler()
 7ExpandedSubBlockStart.gif    {
 8ExpandedSubBlockEnd.gif    }

 9InBlock.gif
10InBlock.gif    public override void Initialize(ConfigurationView configurationView)
11ExpandedSubBlockStart.gif    {
12ExpandedSubBlockEnd.gif    }

13InBlock.gif
14InBlock.gif    public override Exception HandleException(Exception exception, string policyName, Guid correlationID) 
15ExpandedSubBlockStart.gif    {
16InBlock.gif      DialogResult result = this.ShowThreadExceptionDialog(exception);
17InBlock.gif
18InBlock.gif      // Exits the program when the user clicks Abort.
19InBlock.gif      if (result == DialogResult.Abort) 
20InBlock.gif        Application.Exit();
21InBlock.gif
22InBlock.gif      return exception;
23ExpandedSubBlockEnd.gif    }

24InBlock.gif
25InBlock.gif    // Creates the error message and displays it.
26InBlock.gif    private DialogResult ShowThreadExceptionDialog(Exception e) 
27ExpandedSubBlockStart.gif    {
28InBlock.gif      string errorMsg = e.Message + Environment.NewLine + Environment.NewLine;
29InBlock.gif
30InBlock.gif      return MessageBox.Show(errorMsg, "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
31ExpandedSubBlockEnd.gif    }

32ExpandedBlockEnd.gif  }
结束语:异常处理应用程序块的进阶篇就写到这里了。
















本文转自lihuijun51CTO博客,原文链接: http://blog.51cto.com/terrylee/67614  ,如需转载请自行联系原作者


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7月前
|
数据库
SAP ABAP COMMIT WORK 关键字的一些使用要点
SAP ABAP COMMIT WORK 关键字的一些使用要点
60 0
|
机器学习/深度学习 算法 图计算
图学习【参考资料2】-知识补充与node2vec代码注解
1. 回顾并总结了图的基本概念。 2. 学习思考算法实现的代码思路--Node2Vec的实现以及RandomWalk的实现。 3. 对源码阅读能力的提升。