• 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  }

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

    支持TerryLee的创业产品Worktile
    Worktile,新一代简单好用、体验极致的团队协同、项目管理工具,让你和你的团队随时随地一起工作。完全免费,现在就去了解一下吧。
    https://worktile.com
  • 相关阅读:
    用人之道(一) 如何组建软件开发队伍[转]
    用人之道(二) 何管理软件开发团队[转]
    2005年度世界500强公司名单[转]
    人类的15个欲望与游戏设计[转&收藏]
    Flash读取Cookie[转]
    高效程序员应该养成的七个习惯
    六度隔离学说,1967年,哈佛大学,Stanley Milgram
    做技术,切不可沉湎于技术[转&收藏]
    庆祝VSX团队成立,加入VSX团队申请帖
    如何把菜单添加到另外一个VSPackage的菜单里?
  • 原文地址:https://www.cnblogs.com/Terrylee/p/277557.html
Copyright © 2020-2023  润新知