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

  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 (11NOT 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  }

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

posted on 2005-11-16 11:46 TerryLee 阅读(4308) 评论(22)  编辑 收藏 所属分类: Enterprise Library

评论

#1楼  2005-11-16 12:00 極速麻醉      

速度好快啊!对我们这些初学者实在是太好了!
谢谢!   回复  引用  查看    

#2楼 [楼主] 2005-11-16 12:11 Terrylee      

@極速麻醉

我尽量往前赶着写

希望对大家有所帮助:)   回复  引用  查看    

#3楼  2005-11-16 13:09 yanlixin [未注册用户]

很好,前两天还在网上找,一直没找到,后来还是自已研究源码的.今天终于看到了. 谢谢.   回复  引用  查看    

#4楼 [楼主] 2005-11-16 13:16 Terrylee      

@yanlixin

呵呵,别这么客气

大家互相交流嘛:)   回复  引用  查看    

#5楼  2005-11-24 11:34 过客来的 [未注册用户]

写的很棒!强烈支持!
不过忽略了一点,就是如何把这些dll拷贝出来使用.
1.我看了一下共有31个dll,如何编译成单个dll?
2.理论上把dll拷贝到bin目录就可使用,但我看到bin目录中很多配置文件,不解?
3.建议使用最简化方法,就是哪些文件是必须的,有什么作用说明一下,然后直接放到哪些目录里就可使用,这样适合初学者.

最后十分感谢作者的辛勤劳动.   回复  引用  查看    

#6楼 [楼主] 2005-11-24 13:00 Terrylee      

@过客来的

首先特别感谢你的意见

1.对于每一个应用程序块,在里面我都会说要添加哪些DLL
2.最好是把DLL以添加引用的形式,添加到项目中去,那些配置文件是应用程序块必须的,由配置工具操作;
3.我觉得我写的本系列文章,您应该从第一篇开始阅读,在文章中提及的文件,应该都是必须得,另外,最好不要手动拷贝文件,而是按照我说的步骤去做,这样,需要的文件就会自动拷贝到相应的目录下;

这样回答不知道你是否满意?
  回复  引用  查看    

#7楼  2005-11-24 15:47 过客来的 [未注册用户]

谢谢解答!
我想用一个dll和一个config文件就搞定企业库.不知可否?
我在用Visual Web Developer Express 2005.直接拷贝dll到bin目录用,可以通过,配置的话就用企业库自带的工具,我想这更加直截了当,给别人用也方便,拷个dll和config文件过去就可以了,初学见笑了.
我还没下到2.0版的Enterprise Library,不知有何变化?希望能在这看到相关的信息.   回复  引用  查看    

#8楼 [楼主] 2005-11-24 15:54 Terrylee      

@过客来的

呵呵,其实你说的用一个dll和一个config文件这个问题前面有人问过,我一直没有来得及去尝试^_^

2.0版的Enterprise Library还没有正式发布,据说在12月份发布。   回复  引用  查看    

#9楼  2005-11-24 16:18 过客来的 [未注册用户]

回的好快! : )
没办法的啦,2.0还没出来,只好先用1.1版的Enterprise Library .
在NET Framework 2.0上用Enterprise Library 1.1理论上是可以的.(前提是安装了NET Framework 1.1)
努力学习当中.........
  回复  引用  查看    

#10楼  2005-11-24 17:28 过客来的 [未注册用户]

已下载Enterprise Library for .NET 2.0 - November 2005 CTP
下载地址:
http://www.gotdotnet.com/codegallery/codegallery.aspx?id=295a464a-6072-4e25-94e2-91be63527327&lc=2052

另外 Enterprise Library 1.1版的也出了个Patch 1763 补丁。

不理那么多了,目前考虑直接用2.0版本的。   回复  引用  查看    

#11楼 [楼主] 2005-11-24 17:42 Terrylee      

@过客来的

谢谢谢谢,载下来看看先:)   回复  引用  查看    

#12楼  2006-03-08 11:04 六子      

在案例“ExceptionHandlingBasicQuickStart”中用到了“ThreadException事件”,它的作用是“在发生未捕获线程异常时发生。”。
代码(类QuickStartForm的 Main() 下):

// *****************************************
// Creates an instance of the methods that will handle global exceptions.
GlobalExceptionProcessing eh = new GlobalExceptionProcessing();

// Unhandled exceptions will be delivered to our ThreadException handler
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(eh.AppThreadException);

// *****************************************


如果抛出的异常不是“Wrap Policy”,“Replace Policy”等类型,“ThreadException事件”,会自动把类型设置为“Global Policy”。
代码(GlobalExceptionProcessing类中AppThreadException方法):

// *****************************************
bool rethrow = ExceptionPolicy.HandleException(e.Exception, "Global Policy");
// *****************************************

"Global Policy"类的异常会用AppMessageExceptionHandler进行处理。

我有个问题:
如何在ASP.NET中应用“ThreadException事件”?如果不能用“ThreadException事件”事件,有什么替代方案?   回复  引用  查看    

#13楼  2006-10-07 11:07 壮志      

是啊 asp.net中有没有完整的异常解决方案?   回复  引用  查看    

#14楼 [楼主] 2006-10-07 11:20 TerryLee      

@壮志
在ASP.NET中可以在Global文件中处理啊   回复  引用  查看    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-11-16 12:00 编辑过
 
另存  打印
最新IT新闻:
· 阿里巴巴确立未来十年战略规划 修改自身定位
· 微软高管:Wii用户最终会成为Xbox 360用户
· 遵守YouTube案裁定 谷歌将陷入隐私指控深渊
· iPhone入华在即 中国手机产业生存面临考验
· 阿里巴巴集团再向淘宝注资20亿元
 





导航

公告

  • 网名:TerryLee
  • 本名:李会军
  • 位置:中国北京 Ethos
  • 联系方式:
  • 个人主页

 MVP配置

 版权声明

  • 本站采用创作共用许可 署名,非商业

绿色通道

IT新闻

统计

与我联系

留言簿(311)

我的标签

随笔分类