Enterprise Library Step By Step系列(十二):异常处理应用程序块——进阶篇
一.把异常信息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
创建存储过程:
CREATE PROCEDURE WriteLog2
(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 ntext17
)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
FormattedMessage35
)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.至此配置完成,在程序中我们不需要做任何改动(这就是企业库的配置驱动的思想精妙之处^_^)。
/// <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
try9
{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类:
/// <summary>2
/// Summary description for AppTextExceptionFormatter.3
/// </summary> 4
public class AppTextExceptionFormatter : TextExceptionFormatter5
{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
public abstract class ExceptionHandler : ConfigurationProvider, IExceptionHandler该抽象类继承ConfigurationProvider类,并实现IExceptionHandler接口。ConfigurationProvider抽象类实现了IConfigurationProvider接口,用来读取配置数据。
public abstract class ConfigurationProvider : IConfigurationProvider使用支持序列化的数据类型作为配置参数,还有要注意数据类型的简单,避免“Exception Handling Exceptions”
看一下在Enterprise Library Quick Start中提供了定制Handler的实现:
/// <summary>2
/// Summary description for GlobalPolicyExceptionHandler.3
/// </summary>4
public class AppMessageExceptionHandler : ExceptionHandler5
{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
}



浙公网安备 33010602011771号