微软企业库5.0 学习之路——第三步、为项目加上异常处理(采用自定义扩展方式记录到数据库中)...

我们搭建好了项目的整体多数据库环境,实现了项目的多数据库访问,而整个项目中最主要的异常处理却没有进行部署,今天我们就使用企业库中的Exception Handling+Logging模块为项目加上异常处理以及异常日志记录。

(注:关于Exception Handling和Logging模块的相关基本概念可以查看TerryLee的异常处理日志检测这2篇文章)

     首先说一下企业库Logging模块的个人感觉,个人感觉企业库的日志记录太繁琐了,而且要自定义也比较烦,无法通过简单的配置达到我自己的要求,企业库中的日志记录模块在可以记录许多信息如下:

Timestamp: 2010-6-12 3:16:39

Message: HandlingInstanceID: 669fed01-a758-434b-896e-a8e25ebf8c9b
An exception of type 'System.Exception' occurred and was caught.
----------------------------------------------------------------
06/12/2010 11:16:39
Type : System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Message : Test
Source : EntLibStudy.Helper
Help link :
Data : System.Collections.ListDictionaryInternal
TargetSite : System.String Test()
Stack Trace :    在 EntLibStudy.Helper.BasePage.Test() 位置 F:\EntLibStudy\Helper\BasePage.cs:行号 87
   在 EntLibStudy.Helper.BasePage.<Page_Load>b__0() 位置 F:\EntLibStudy\Helper\BasePage.cs:行号 81
   在 Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionManagerImpl.Process[TResult](Func`1 action, TResult defaultResult, String policyName) 位置

以下省略N行。。。。。。

这些信息很多都不是我想要的,我想要的仅仅是异常的提示信息,异常发生的时间,以及异常发生的位置,好方便我们第一时间到异常发生的源头进行调试检查(可能企业库的这些异常信息更加有用,但是我个人认为很多时候都会干扰我们),所以我们仅仅需要其中的几条有用的信息就够了,比如Message,Timestamp、Stack Trace和Severity这4个就基本上够用了,所以我做了个处理,就是使用企业库中Logging模块提供的自定义CustomerTraceListener来实现我们需要的功能。

首先建立一个异常日志记录表(SQLite版)

1CREATE TABLE [ExceptionLog] (
2    [Id] integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3    [Message] nvarchar(1024) NOT NULL,
4    [LogDate] nvarchar(1024) NOT NULL,
5    [ExceptionLevel] nvarchar(32) NOT NULL,
6    [Exception] ntext NOT NULL
7)

我编写了一个类继承自CustomTraceListener,并重写了记录方法,具体代码如下:

001using System;
002using System.Collections.Generic;
003using System.Data;
004using System.Data.Common;
005using System.Diagnostics;
006using System.Globalization;
007using System.Linq;
008using System.Text;
009  
010using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
011using Microsoft.Practices.EnterpriseLibrary.Data;
012using Microsoft.Practices.EnterpriseLibrary.Logging;
013using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
014using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
015using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
016  
017namespace EntLibStudy.Helper.EntLibExtension.ExceptionExtension
018{
019    [ConfigurationElementType(typeof(CustomTraceListenerData))]
020    public class ExceptionCustomerListener : CustomTraceListener
021    {
022        string writeLogSQL = String.Empty;
023        Database database;
024        Exception ex;
025  
026        public ExceptionCustomerListener()
027            : base()
028        {
029            database = DBHelper.CreateDataBase();
030        }
031  
032        public override void TraceData(TraceEventCache eventCache, string source,
033            TraceEventType eventType, int id, object data)
034        {
035            if ((this.Filter == null) || this.Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data, null))
036            {
037                if (data is LogEntry)
038                {
039                    LogEntry logEntry = data as LogEntry;
040                    ExecuteSQL(logEntry);
041                }
042                else if (data is string)
043                {
044                    Write(data as string);
045                }
046                else
047                {
048                    base.TraceData(eventCache, source, eventType, id, data);
049                }
050            }
051        }
052  
053        public override void Write(string message)
054        {
055            ExecuteWriteLogSQL(TraceEventType.Information, DateTime.Now, message, database);
056        }
057  
058        public override void WriteLine(string message)
059        {
060            Write(message);
061        }
062  
063        /// <summary>
064        ///执行SQL
065        /// </summary>
066        /// <param name="logEntry">日志对象</param>
067        private void ExecuteSQL(LogEntry logEntry)
068        {
069            using (DbConnection connection = database.CreateConnection())
070            {
071                try
072                {
073                    connection.Open();
074                    using (DbTransaction transaction = connection.BeginTransaction())
075                    {
076                        try
077                        {
078                            ExecuteWriteLogSQL(logEntry, database, transaction);
079                            transaction.Commit();
080                        }
081                        catch
082                        {
083                            transaction.Rollback();
084                            throw;
085                        }
086                    }
087                }
088                finally
089                {
090                    connection.Close();
091                }
092            }
093        }
094  
095        /// <summary>
096        /// 执行写入日志数据库语句
097        /// </summary>
098        /// <param name="severity">异常等级</param>
099        /// <param name="message">消息</param>
100        /// <param name="db">保存日志的数据库实例</param>
101        private void ExecuteWriteLogSQL(TraceEventType severity, DateTime timeStamp, string message, Database db)
102        {
103            writeLogSQL = (string)this.Attributes["writeLogSQL"];
104            DbCommand cmd = db.GetSqlStringCommand(writeLogSQL);
105            string exceptionMessage = Utils.GetBetweenString(message, "Message :", "Source :", 9);
106            string exceptionInfo = Utils.GetBetweenString(message, "Stack Trace :", "Additional Info:", 13);
107            db.AddInParameter(cmd, "@Message", DbType.String, exceptionMessage);
108            db.AddInParameter(cmd, "@LogDate", DbType.DateTime, timeStamp);
109            db.AddInParameter(cmd, "@Level", DbType.String, message);
110            db.AddInParameter(cmd, "@Exception", DbType.String, exceptionInfo);
111            db.ExecuteNonQuery(cmd);
112        }
113  
114        /// <summary>
115        /// 执行写入日志数据库语句
116        /// </summary>
117        /// <param name="logEntry">日志对象</param>
118        /// <param name="db">保存日志的数据库实例</param>
119        /// <param name="transaction">事务对象</param>
120        private void ExecuteWriteLogSQL(LogEntry logEntry, Database db, DbTransaction transaction)
121        {
122            writeLogSQL = (string)this.Attributes["writeLogSQL"];
123            DbCommand cmd = db.GetSqlStringCommand(writeLogSQL); 
124            string exceptionMessage = Utils.GetBetweenString(logEntry.Message, "Message :", "Source :", 9);
125            string exceptionInfo = Utils.GetBetweenString(logEntry.Message, "Stack Trace :", "Additional Info:", 13);
126            db.AddInParameter(cmd, "@Message", DbType.String, exceptionMessage);
127            db.AddInParameter(cmd, "@LogDate", DbType.DateTime, logEntry.TimeStamp.ToLocalTime());
128            db.AddInParameter(cmd, "@Level", DbType.String, logEntry.LoggedSeverity);
129            db.AddInParameter(cmd, "@Exception", DbType.String, exceptionInfo);
130            db.ExecuteNonQuery(cmd, transaction);
131        }
132    }
133}

其中在类的初始化的时候获取配置文件的默认数据库对象,通过重写TraceData方法来调用ExecuteSQL方法来执行异常日志插入。

在ExecuteWriteLogSQL方法中有句代码:

 

1writeLogSQL = (string)this.Attributes["writeLogSQL"];

这个代码就是从配置文件中Listener的Attributes中获取所配置的执行SQL语句(这里不同于Logging模块自带的数据库以存储过程的记录方式,而是使用配置的SQL语句的方式,因为本项目是面向多数据库的,并不是所有的数据库都有存储过程的,比如SQLite),下面看下具体的配置信息:

pic14

配置文件创建主要分为以下2步:

1、在企业库的配置工具添加一个Exception Handle模块,然后添加一个名为Exception Policy的策略,再为这个策略添加异常类型,默认我选择所有异常类型(All Exceptions),Post Handle Action为: NotifyRethow(对不理解Post Handle Action的处理方式的可以看下下面的解释)

PostHandlingAction 决定了在异常处理链完成后将发生什么活动。默认情况下,PostHandlingAction 被设置为 NotifyRethrow 。
None:应用程序块为此异常执行所有的处理程序,然后在 HandleException 方法的调用点上返回 false 给应用程序。应用程序检查此值以继续运行。
NotifyRethrow:应用程序块为此异常执行所有的处理程序,然后在 HandleException 方法的调用点上返回 true 给应用程序。应用程序检查到此值就重新抛出原始异常。
ThrowNewException:应用程序块为此异常执行所有的处理程序,然后在所有处理程序运行后抛出存在的异常。

2、为异常策略创建处理方式,我这边选择Loggin Exception Handler(在创建的同时配置工具会我们自动创建好Logging模块,并自动创建了一个日志分类:General,不过这个日志分类的默认Listener为event log,就是记录到系统的事件中),这时我们再创建一个CustomerTraceListener选择From File->自定义Listener所在DLL。

这边我碰到了一个问题就是添加了CustomerTraceListener,在对话框中我点击From File选择我编写的自定义Listener所在DLL,可惜没任何反应,不知道是不是要在DLL中做什么处理,所以我只能采用老办法:手写配置文件

首先看下Exception Handle模块的配置信息:

01<exceptionHandling>
02    <exceptionPolicies>
03      <add name="ExceptionPolicy">
04        <exceptionTypes>
05          <add name="All Exceptions" type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
06            postHandlingAction="NotifyRethrow">
07            <exceptionHandlers>
08              <add name="Logging Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
09                logCategory="General" eventId="100" severity="Error" title="Enterprise Library Exception Handling"
10                formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
11                priority="0" />
12            </exceptionHandlers>
13          </add>
14        </exceptionTypes>
15      </add>
16    </exceptionPolicies>
17  </exceptionHandling>

 

接下来是日志模块配置,在日志模块下我配置了3个Listener,其中Custom Trace Listener为我自定义的异常日志记录,Event Log Listener(系统日志记录)Rolling Flat File Trace Listener(文本文件记录,按天回滚记录)为在日志分类General无法正常记录日志时的记录下日志分类General为何无法记录,因为异常日志默认保存到数据库中,但是如果数据库中存在问题,或者链接被关闭这时就无法正常记录异常,所以:

01<loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
02    <listeners>
03      <add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging"
04        writeLogSQL="insert into ExceptionLog(Message,LogDate,ExceptionLevel,Exception) values(@Message,@LogDate,@Level,@Exception)"
05        type="EntLibStudy.Helper.EntLibExtension.ExceptionExtension.ExceptionCustomerListener, EntLibStudy.Helper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
06        traceOutputOptions="None" name="Custom Trace Listener" initializeData=""
07        formatter="Text Formatter" />
08      <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
09        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
10        source="Enterprise Library Logging" formatter="Text Formatter"
11        log="" machineName="." traceOutputOptions="None" />
12      <add name="Rolling Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
13        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
14        fileName="rolling.log" formatter="Text Formatter" rollInterval="Day" />
15    </listeners>
16    <formatters>
17      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
18        template="Timestamp: {timestamp}{newline}
19Message: {message}{newline}
20Category: {category}{newline}
21Priority: {priority}{newline}
22EventId: {eventid}{newline}
23Severity: {severity}{newline}
24Title:{title}{newline}
25Machine: {localMachine}{newline}
26App Domain: {localAppDomain}{newline}
27ProcessId: {localProcessId}{newline}
28Process Name: {localProcessName}{newline}
29Thread Name: {threadName}{newline}
30Win32 ThreadId:{win32ThreadId}{newline}
31Extended Properties: {dictionary({key} - {value}{newline})}"
32        name="Text Formatter" />
33    </formatters>
34    <categorySources>
35      <add switchValue="All" name="General">
36        <listeners>
37          <add name="Custom Trace Listener" />
38        </listeners>
39      </add>
40    </categorySources>
41    <specialSources>
42      <allEvents switchValue="All" name="All Events" />
43      <notProcessed switchValue="All" name="Unprocessed Category" />
44      <errors switchValue="All" name="Logging Errors & Warnings">
45        <listeners>
46          <add name="Event Log Listener" />
47          <add name="Rolling Flat File Trace Listener" />
48        </listeners>
49      </errors>
50    </specialSources>
51  </loggingConfiguration>

 

在配置完后我们就可以进行代码编写,在页面里进行异常控制。

在ASP.NET中,异常处理主要有4种,执行顺序为:Page_Error事件>ErrorPage属性>Application_Error事件> <customErrors>,我这边采用Page_Error,由于在本项目中我已经建立了BasePage,所有的页面都继承这个页面,所以我只需在这个页面中编写Page_Error事件:

01protected void Page_Error(object sender, EventArgs e)
02        {
03            //获取最新的异常信息
04            var ex = Server.GetLastError();
05            //处理异常
06            HandleException(ex, "ExceptionPolicy");
07            //清空异常
08            Server.ClearError();
09        }
10        /// <summary>
11        /// 异常处理方法
12        /// </summary>
13        /// <param name="ex">异常信息</param>
14        /// <param name="policy">异常处理策略</param>
15        protected void HandleException(Exception ex, string policy)
16        {
17            bool rethrow = false;
18            var exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();
19            rethrow = exManager.HandleException(ex, policy);
20            if (rethrow)
21            {
22                this.RedirectPermanent("~/error.aspx");
23            }
24        }

 

其中exManager.HandleException(ex, policy)为根据策略名处理异常,我这边使用的ExceptionPolicy,这个策略的处理方式为异常日志记录,它会帮我们调用到我们自定义的ExceptionCustomerListener 类,进行异常日志记录。

这样我们就完成了统一捕获系统中发生的异常了,本文也到此结束,欢迎大家指点!

转载于:https://www.cnblogs.com/hurenwang/archive/2011/01/15/1936475.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值