zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    Java实现 LeetCode 803 打砖块 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    Java实现 LeetCode 803 打砖块 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    英文标点
    post sharp 与log4net 结合使用,含执行源码 转拷
  • 原文地址:https://www.cnblogs.com/Terrylee/p/277557.html
Copyright © 2011-2022 走看看