一.把異常信息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,具體的配置方法在日志和監測應用程序塊中講過了,這裡就不重復了,我們看一下它的配置:
注意設置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 }
補充一點:在項目中要添加對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 }
結束語:異常處理應用程序塊的進階篇就寫到這裡了。