Enterprise Library Step By Step系列(十二):異常處理應(yīng)用程序塊——進(jìn)階篇
作者:Terrylee
一.把異常信息Logging到數(shù)據(jù)庫
在日志和監(jiān)測(cè)應(yīng)用程序塊中,有朋友提意見說希望能夠把異常信息Logging到數(shù)據(jù)庫中,在這里介紹一下具體的實(shí)現(xiàn)方法。
1.創(chuàng)建相關(guān)的數(shù)據(jù)庫環(huán)境:
我們可以用日志和監(jiān)測(cè)應(yīng)用程序塊自帶的SQL語句來創(chuàng)建相關(guān)的數(shù)據(jù)庫環(huán)境:
創(chuàng)建數(shù)據(jù)庫:
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%)創(chuàng)建表:
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
創(chuàng)建存儲(chǔ)過程:
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語句默認(rèn)的路徑為C:\Program Files\Microsoft Enterprise Library\src\Logging\Sinks\Database\Scripts,直接運(yùn)行CreateLoggingDatabase.cmd即可。
2.運(yùn)行配置工具,我們創(chuàng)建一個(gè)日志和監(jiān)測(cè)應(yīng)用程序塊,并建一個(gè)Database Sink,具體的配置方法在日志和監(jiān)測(cè)應(yīng)用程序塊中講過了,這里就不重復(fù)了,我們看一下它的配置:
注意設(shè)置StoredProcName為WriteLog,就是我們剛才創(chuàng)建的存儲(chǔ)過程。
3.同時(shí)再創(chuàng)建一個(gè)Category,起名為DataException,并設(shè)置它的Sink為Database Sink。
4.設(shè)置Logging Handler的LogCategory為我們剛才創(chuàng)建的DataException,其他的參數(shù)暫時(shí)默認(rèn)。
5.至此配置完成,在程序中我們不需要做任何改動(dòng)(這就是企業(yè)庫的配置驅(qū)動(dòng)的思想精妙之處^_^)。
/// <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
}補(bǔ)充一點(diǎn):在項(xiàng)目中要添加對(duì)Microsoft.Practices.EnterpriseLibrary.Logging.Sinks.Database.dll的引用
二.異常的傳播機(jī)制
異常的傳播機(jī)制有以下幾種:
l 異常自動(dòng)傳播
l 在同一層內(nèi)部,捕獲或者再拋出原有異常
l 捕獲,包裝和拋出包裝后的異常
我們不推薦直接拋出原有異常,因?yàn)閻阂獾挠脩裟軌驈南到y(tǒng)診斷信息中得知應(yīng)用的詳細(xì)情況,并從中查找應(yīng)用的弱點(diǎn)。異常應(yīng)用程序塊提供了一旦配置的Handler執(zhí)行后,就產(chǎn)生對(duì)應(yīng)的post-handling動(dòng)作,該動(dòng)作有如下選項(xiàng):
None - 沒有重拋異常的動(dòng)作。
NotifyRethrow - 告訴調(diào)用程序:Policy推薦應(yīng)該重拋異常。
ThrowNewException - 在所有的Handler執(zhí)行后,向調(diào)用程序拋出最終異常(并不一定是原始的異常)。
三.異常的格式化
可以格式化任何System.Exception類型的異常
能夠用來記錄或者顯示異常的詳細(xì)信息
字符型格式化器——TextExceptionFormatter:創(chuàng)建在一個(gè)屏幕上,日志中或以其他形式表現(xiàn)的,可以表現(xiàn)異常信息的詳細(xì)記錄
XML格式化器——XMLExceptionFormatter:針對(duì)一個(gè)異常,創(chuàng)建一個(gè)用XML表現(xiàn)形式表現(xiàn)記錄,每一個(gè)異常的屬性,均可以被存儲(chǔ)為XML元素。
看一下在Enterprise Library Quick Start中提供的自定義的ExceptionFormatter,實(shí)現(xiàn)了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
}四.創(chuàng)建自定義的異常處理器
異常處理應(yīng)用程序塊允許您包裝并使用您自己的例外業(yè)務(wù)處理流程,例如在時(shí)間記錄系統(tǒng)中填寫一個(gè)事件,利用業(yè)務(wù)規(guī)范進(jìn)行包裝和替代,利用另外的記錄系統(tǒng)進(jìn)行記錄(比較常用的有Log4net,前段時(shí)間深淵野魚介紹的,還沒用過^_^),這種靈活的可配置性,將允許您在不同的異常類型及其策略中靈活的配置。
可以通過實(shí)現(xiàn)ExceptionHandler抽象類,來創(chuàng)建定制的Handler
public abstract class ExceptionHandler : ConfigurationProvider, IExceptionHandler該抽象類繼承ConfigurationProvider類,并實(shí)現(xiàn)IExceptionHandler接口。ConfigurationProvider抽象類實(shí)現(xiàn)了IConfigurationProvider接口,用來讀取配置數(shù)據(jù)。
public abstract class ConfigurationProvider : IConfigurationProvider使用支持序列化的數(shù)據(jù)類型作為配置參數(shù),還有要注意數(shù)據(jù)類型的簡(jiǎn)單,避免“Exception Handling Exceptions”
看一下在Enterprise Library Quick Start中提供了定制Handler的實(shí)現(xiàn):
/// <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
}
結(jié)束語:異常處理應(yīng)用程序塊的進(jìn)階篇就寫到這里了。
Worktile,新一代簡(jiǎn)單好用、體驗(yàn)極致的團(tuán)隊(duì)協(xié)同、項(xiàng)目管理工具,讓你和你的團(tuán)隊(duì)隨時(shí)隨地一起工作。完全免費(fèi),現(xiàn)在就去了解一下吧。
https://worktile.com



浙公網(wǎng)安備 33010602011771號(hào)