分享

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

 贾朋亮博客 2014-12-04
Enterprise Library Step By Step系列(十二):异常处理应用程序块——进阶篇

作者:Terrylee

一.把异常信息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

创建存储过程:

1CREATE 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)
18AS

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
)
51GO

SQL语句默认的路径为C:\Program Files\Microsoft Enterprise Library\src\Logging\Sinks\Database\Scripts,直接运行CreateLoggingDatabase.cmd即可。

2.运行配置工具,我们创建一个日志和监测应用程序块,并建一个Database Sink,具体的配置方法在日志和监测应用程序块中讲过了,这里就不重复了,我们看一下它的配置:

注意设置StoredProcNameWriteLog,就是我们刚才创建的存储过程。

3.同时再创建一个Category,起名为DataException,并设置它的SinkDatabase Sink

4.设置Logging HandlerLogCategory为我们刚才创建的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 }

补充一点:在项目中要添加对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
}

四.创建自定义的异常处理器

异常处理应用程序块允许您包装并使用您自己的例外业务处理流程,例如在时间记录系统中填写一个事件,利用业务规范进行包装和替代,利用另外的记录系统进行记录(比较常用的有Log4net,前段时间深渊野鱼介绍的,还没用过^_^),这种灵活的可配置性,将允许您在不同的异常类型及其策略中灵活的配置。

可以通过实现ExceptionHandler抽象类,来创建定制的Handler

1public abstract class ExceptionHandler : ConfigurationProvider, IExceptionHandler

该抽象类继承ConfigurationProvider类,并实现IExceptionHandler接口。ConfigurationProvider抽象类实现了IConfigurationProvider接口,用来读取配置数据。

1public 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 }

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多