一.把异常信息
Logging
到数据库
在日志和监测应用程序块中,有朋友提意见说希望能够把异常信息
Logging
到数据库中,在这里介绍一下具体的实现方法。
1.创建相关的数据库环境:
我们可以用日志和监测应用程序块自带的
SQL
语句来创建相关的数据库环境:
创建数据库:
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
%
)
创建表:
CREATE
TABLE
[
dbo
]
.
[
Log
]
(
[ LogID ] [ int ] IDENTITY ( 1 , 1 ) NOT NULL ,
[ EventID ] [ int ] NULL ,
[ Category ] [ nvarchar ] ( 64 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ Priority ] [ int ] NOT NULL ,
[ Severity ] [ nvarchar ] ( 32 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ Title ] [ nvarchar ] ( 256 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ Timestamp ] [ datetime ] NOT NULL ,
[ MachineName ] [ nvarchar ] ( 32 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ AppDomainName ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ ProcessID ] [ nvarchar ] ( 256 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ ProcessName ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ ThreadName ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ Win32ThreadId ] [ nvarchar ] ( 128 ) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ Message ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ FormattedMessage ] [ ntext ] COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [ PRIMARY ] TEXTIMAGE_ON [ PRIMARY ]
GO
[ LogID ] [ int ] IDENTITY ( 1 , 1 ) NOT NULL ,
[ EventID ] [ int ] NULL ,
[ Category ] [ nvarchar ] ( 64 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ Priority ] [ int ] NOT NULL ,
[ Severity ] [ nvarchar ] ( 32 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ Title ] [ nvarchar ] ( 256 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ Timestamp ] [ datetime ] NOT NULL ,
[ MachineName ] [ nvarchar ] ( 32 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ AppDomainName ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ ProcessID ] [ nvarchar ] ( 256 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ ProcessName ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[ ThreadName ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ Win32ThreadId ] [ nvarchar ] ( 128 ) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ Message ] [ nvarchar ] ( 2048 ) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[ FormattedMessage ] [ ntext ] COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [ PRIMARY ] TEXTIMAGE_ON [ PRIMARY ]
GO
创建存储过程:
1
CREATE
PROCEDURE
WriteLog
2 (
3 @EventID int ,
4 @Category nvarchar ( 64 ),
5 @Priority int ,
6 @Severity nvarchar ( 32 ),
7 @Title nvarchar ( 256 ),
8 @Timestamp datetime ,
9 @MachineName nvarchar ( 32 ),
10 @AppDomainName nvarchar ( 2048 ),
11 @ProcessID nvarchar ( 256 ),
12 @ProcessName nvarchar ( 2048 ),
13 @ThreadName nvarchar ( 2048 ),
14 @Win32ThreadId nvarchar ( 128 ),
15 @Message nvarchar ( 2048 ),
16 @FormattedMessage ntext
17 )
18 AS
19
20 INSERT INTO [ Log ] (
21 EventID,
22 Category,
23 Priority,
24 Severity,
25 Title,
26 [ Timestamp ] ,
27 MachineName,
28 AppDomainName,
29 ProcessID,
30 ProcessName,
31 ThreadName,
32 Win32ThreadId,
33 Message,
34 FormattedMessage
35 )
36 VALUES (
37 @EventID ,
38 @Category ,
39 @Priority ,
40 @Severity ,
41 @Title ,
42 @Timestamp ,
43 @MachineName ,
44 @AppDomainName ,
45 @ProcessID ,
46 @ProcessName ,
47 @ThreadName ,
48 @Win32ThreadId ,
49 @Message ,
50 @FormattedMessage )
51 GO
2 (
3 @EventID int ,
4 @Category nvarchar ( 64 ),
5 @Priority int ,
6 @Severity nvarchar ( 32 ),
7 @Title nvarchar ( 256 ),
8 @Timestamp datetime ,
9 @MachineName nvarchar ( 32 ),
10 @AppDomainName nvarchar ( 2048 ),
11 @ProcessID nvarchar ( 256 ),
12 @ProcessName nvarchar ( 2048 ),
13 @ThreadName nvarchar ( 2048 ),
14 @Win32ThreadId nvarchar ( 128 ),
15 @Message nvarchar ( 2048 ),
16 @FormattedMessage ntext
17 )
18 AS
19
20 INSERT INTO [ Log ] (
21 EventID,
22 Category,
23 Priority,
24 Severity,
25 Title,
26 [ Timestamp ] ,
27 MachineName,
28 AppDomainName,
29 ProcessID,
30 ProcessName,
31 ThreadName,
32 Win32ThreadId,
33 Message,
34 FormattedMessage
35 )
36 VALUES (
37 @EventID ,
38 @Category ,
39 @Priority ,
40 @Severity ,
41 @Title ,
42 @Timestamp ,
43 @MachineName ,
44 @AppDomainName ,
45 @ProcessID ,
46 @ProcessName ,
47 @ThreadName ,
48 @Win32ThreadId ,
49 @Message ,
50 @FormattedMessage )
51 GO
该
SQL
语句默认的路径为
C:\Program Files\Microsoft Enterprise Library\src\Logging\Sinks\Database\Scripts
,直接运行
CreateLoggingDatabase.cmd
即可。
2.运行配置工具,我们创建一个日志和监测应用程序块,并建一个Database Sink,具体的配置方法在日志和监测应用程序块中讲过了,这里就不重复了,我们看一下它的配置:
注意设置
StoredProcName
为
WriteLog
,就是我们刚才创建的存储过程。
3.同时再创建一个Category,起名为DataException,并设置它的Sink为Database Sink。
4.设置Logging Handler的LogCategory为我们刚才创建的DataException,其他的参数暂时默认。
5.至此配置完成,在程序中我们不需要做任何改动(这就是企业库的配置驱动的思想精妙之处^_^)。
1
/// <summary>
2 /// 日志策略
3 /// </summary>
4 /// <param name="sender"></param>
5 /// <param name="e"></param>
6 private void btn_Log_Click( object sender, System.EventArgs e)
7 {
8 try
9 {
10 Exception ex = new Exception();
11 throw ex;
12 }
13 catch(Exception ex)
14 {
15 bool Flag = ExceptionPolicy.HandleException(ex,"Log Policy");
16
17 if(Flag)
18 {
19 throw;
20 }
21 }
22 }
2 /// 日志策略
3 /// </summary>
4 /// <param name="sender"></param>
5 /// <param name="e"></param>
6 private void btn_Log_Click( object sender, System.EventArgs e)
7 {
8 try
9 {
10 Exception ex = new Exception();
11 throw ex;
12 }
13 catch(Exception ex)
14 {
15 bool Flag = ExceptionPolicy.HandleException(ex,"Log Policy");
16
17 if(Flag)
18 {
19 throw;
20 }
21 }
22 }
补充一点:在项目中要添加对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
/// <summary>
2 /// Summary description for AppTextExceptionFormatter.
3 /// </summary>
4 public class AppTextExceptionFormatter : TextExceptionFormatter
5 {
6 public AppTextExceptionFormatter(TextWriter writer, Exception exception)
7 : base (writer, exception)
8 {
9 }
10
11 protected override void WriteDescription()
12 {
13 // An exception of type {0} occurred and was caught.
14 string line = String.Format("An exception of type {0} occurred and was caught.", base.Exception.GetType().FullName);
15 this.Writer.WriteLine(line);
16 }
17
18 protected override void WriteExceptionType(Type exceptionType)
19 {
20 base.Indent();
21 base.Writer.WriteLine("Type : {0}", exceptionType.FullName);
22 }
23
24 public override void Format()
25 {
26 //this.Writer.WriteLine("Message : {0}", message);
27 this.WriteDescription();
28 //this.WriteExceptionType(base.Exception.GetType());
29 base.WriteMessage(base.Exception.Message);
30 }
31
32 }
2 /// Summary description for AppTextExceptionFormatter.
3 /// </summary>
4 public class AppTextExceptionFormatter : TextExceptionFormatter
5 {
6 public AppTextExceptionFormatter(TextWriter writer, Exception exception)
7 : base (writer, exception)
8 {
9 }
10
11 protected override void WriteDescription()
12 {
13 // An exception of type {0} occurred and was caught.
14 string line = String.Format("An exception of type {0} occurred and was caught.", base.Exception.GetType().FullName);
15 this.Writer.WriteLine(line);
16 }
17
18 protected override void WriteExceptionType(Type exceptionType)
19 {
20 base.Indent();
21 base.Writer.WriteLine("Type : {0}", exceptionType.FullName);
22 }
23
24 public override void Format()
25 {
26 //this.Writer.WriteLine("Message : {0}", message);
27 this.WriteDescription();
28 //this.WriteExceptionType(base.Exception.GetType());
29 base.WriteMessage(base.Exception.Message);
30 }
31
32 }
四.创建自定义的异常处理器
异常处理应用程序块允许您包装并使用您自己的例外业务处理流程,例如在时间记录系统中填写一个事件,利用业务规范进行包装和替代,利用另外的记录系统进行记录(比较常用的有
Log4net
,前段时间
深渊野鱼
介绍的,还没用过
^_^
),这种灵活的可配置性,将允许您在不同的异常类型及其策略中灵活的配置。
可以通过实现
ExceptionHandler
抽象类,来创建定制的
Handler
1
public
abstract
class
ExceptionHandler : ConfigurationProvider, IExceptionHandler
该抽象类继承
ConfigurationProvider
类,并实现
IExceptionHandler
接口。
ConfigurationProvider
抽象类实现了
IConfigurationProvider
接口,用来读取配置数据。
1
public
abstract
class
ConfigurationProvider : IConfigurationProvider
使用支持序列化的数据类型作为配置参数,还有要注意数据类型的简单,避免“
Exception Handling Exceptions
”
看一下在
Enterprise Library Quick Start
中提供了定制
Handler
的实现:
1
/// <summary>
2 /// Summary description for GlobalPolicyExceptionHandler.
3 /// </summary>
4 public class AppMessageExceptionHandler : ExceptionHandler
5 {
6 public AppMessageExceptionHandler()
7 {
8 }
9
10 public override void Initialize(ConfigurationView configurationView)
11 {
12 }
13
14 public override Exception HandleException(Exception exception, string policyName, Guid correlationID)
15 {
16 DialogResult result = this.ShowThreadExceptionDialog(exception);
17
18 // Exits the program when the user clicks Abort.
19 if (result == DialogResult.Abort)
20 Application.Exit();
21
22 return exception;
23 }
24
25 // Creates the error message and displays it.
26 private DialogResult ShowThreadExceptionDialog(Exception e)
27 {
28 string errorMsg = e.Message + Environment.NewLine + Environment.NewLine;
29
30 return MessageBox.Show(errorMsg, "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
31 }
32 }
2 /// Summary description for GlobalPolicyExceptionHandler.
3 /// </summary>
4 public class AppMessageExceptionHandler : ExceptionHandler
5 {
6 public AppMessageExceptionHandler()
7 {
8 }
9
10 public override void Initialize(ConfigurationView configurationView)
11 {
12 }
13
14 public override Exception HandleException(Exception exception, string policyName, Guid correlationID)
15 {
16 DialogResult result = this.ShowThreadExceptionDialog(exception);
17
18 // Exits the program when the user clicks Abort.
19 if (result == DialogResult.Abort)
20 Application.Exit();
21
22 return exception;
23 }
24
25 // Creates the error message and displays it.
26 private DialogResult ShowThreadExceptionDialog(Exception e)
27 {
28 string errorMsg = e.Message + Environment.NewLine + Environment.NewLine;
29
30 return MessageBox.Show(errorMsg, "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
31 }
32 }
结束语:异常处理应用程序块的进阶篇就写到这里了。
本文转自lihuijun51CTO博客,原文链接:
http://blog.51cto.com/terrylee/67614
,如需转载请自行联系原作者