65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Web.config 配置异常

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (4投票s)

2004年4月23日

3分钟阅读

viewsIcon

59974

downloadIcon

202

一篇关于使用自定义处理程序,通过自定义配置节处理异常的文章,使其独立于应用程序的使用。

引言

在大型企业环境中处理异常一直是个问题,您希望以不同的方式处理不同的异常。 虽然可以在web.config中配置错误页面,但仅适用于 HTTP 特定错误。 您无法定义具有各自处理程序的特定异常类型。 我在网上找到的一个解决方案是异常管理块。 但根据我的看法,这毕竟是一个复杂的解决方案。 因此,我设计了自己的机制来在web.config中配置异常类型及其各自的处理程序。

问题定义

通常,在一个简单的应用程序中,我们使用 Try-Catch 块来处理异常,如下所示

Try 
   // Do some code here
Catch sqle as SQLExceptions 
    // Handle SQLException differently
Catch e as Exceptions 
    // Handle Generic Exception differently
End Try

这对于一个简单的应用程序来说没问题,但对于一个可能有多个页面引发异常的企业应用程序来说,单独配置这些块可能会很麻烦。 此外,如果您已经派生了自己的应用程序特定异常,则必须单独处理它们,并且如果您想对异常处理进行任何更改,则必须深入到 aspx 页面中。

建议解决方案

为了克服这个问题,我定义了一个自定义配置节,该节定义了异常类型、其错误处理程序(程序集和类)和重定向 URL。 这样,您可以配置异常、其处理程序(程序集和类)和重定向 URL,而无需以独立的方式干预您之前编写的代码。

配置和处理异常

首先,我们必须在web.config中定义一个自定义配置节,就在<configuration>标记下方。

    <configSections >
        <section name="exceptionManagers" 
          type="ExceptionManagers.ExceptionManagersHandler,ExceptionManagers" />
     </configSections>

就在结束<configuration>标记之前,写入以下内容

<exceptionManagers>
    <exceptionManager application="MyApplication">
        <exceptions>
            <exception name="System.SQLException" url="ErrorPage.aspx">
                <exceptionHandler assembly="ExceptionManagers" 
                                name="SQLExceptionHandler" />
            </exception>
        </exceptions>
    </exceptionManager>
    <exceptionManager application="MyApplication">
        <exceptions>
            <exception name="System.InvalidOperationException" 
                                            url="ErrorPage.aspx">
                <exceptionHandler assembly="ExceptionManagers" 
                       name="InvalidOperationExceptionHandler" />
            </exception>
        </exceptions>
    </exceptionManager>
</exceptionManagers>

上面的部分定义了一个类型为System.SQLException的异常,如果应用程序“MyApplication”中引发该异常,它将由来自ExceptionManagers程序集的SQLExceptionHandler类处理,并且在处理后,它将被重定向到ErrorPage.aspx。 您可以通过复制<ExceptionManager>标记并设置其属性来定义所有其他要处理的异常。 通过以这种方式定义处理程序,我们可以将异常处理逻辑与写入代码(Try-Catch 块)隔离。 我们要做的只是在我们的 Try-Catch 块中放入一行代码,如下所示。

Try 
  //Do Some Code here , that raises Exception
  Catch sqle as SQLException 
    Response.Redirect( ExceptionManagersHandler.PublishException("MyApplication",_
                                                                             sqle) )
  Catch exc as Exception 
    Response.Redirect(ExceptionManagersHandler.PublishException("MyApplication",_
                                                                              exc) )
End Try

此行简单地调用类ExceptionManagersHandler的共享方法PublicshException,并将引发此异常的应用程序的名称和异常对象本身传递给它。

使用代码

要定义异常处理程序,请创建一个类库项目并将其命名为ExceptionManagers(这是exceptionHandler标记中的程序集名称)。 现在,添加一个类SQLExceptionHandler来处理SQLException。 此类实现IExceptionHandler,一个定义了单个executeHandler方法的接口。 当引发SQLException类型的异常并且调用ExceptionManager.PublishException时,它会从web.config中检索配置设置并搜索异常的适当处理程序。 然后,该方法使用Reflection命名空间来实例化处理程序并委托对它的调用。 所述类的代码如下

' This Class implements the IConfigurationSectionHandler interface and 
' reads the configuration settings and returns a hashtable based on the 
' current settings in web.config

Option Strict On
Imports System
Imports System.Collections
Imports System.Xml
Imports System.Configuration
Imports System.Reflection

Public Class ExceptionManagersHandler
    Implements IConfigurationSectionHandler

    'This method reads the configuration section of the 
    'web.config and returns a hashtable 
    'populated with all the information od exceptions and their handlers
    ' Hashtable contains ExceptionInfo class's objects 

    Public Function Create(ByVal parent As Object, _
            ByVal configContext As Object, ByVal section As XmlNode) _
            As Object Implements IConfigurationSectionHandler.Create

        Dim _HandlerBucket As New Hashtable()
        Dim appName, exceptionName, redirectUrl, _
                 errorHandler, assemblyName As String
        Dim managerNode, exceptionNode, handlerNode As XmlNode
        Dim managersNL, exceptionsNL, handlersNL As XmlNodeList
        Dim exceptionsList As Hashtable
        Dim excepInfo As ExceptionInfo

        managersNL = section.SelectNodes("//exceptionManager")
        For Each managerNode In managersNL
            appName = managerNode.Attributes.GetNamedItem("application").Value
            exceptionsNL = managerNode.SelectNodes("exceptions/exception")
            For Each exceptionNode In exceptionsNL
                exceptionsList = New Hashtable()
                exceptionName = _
                  exceptionNode.Attributes.GetNamedItem("name").Value
                redirectUrl = _
                  exceptionNode.Attributes.GetNamedItem("url").Value
                excepInfo = _
                  New ExceptionInfo(appName, exceptionName, redirectUrl)
                handlersNL = exceptionNode.SelectNodes("exceptionHandler")
                For Each handlerNode In handlersNL
                    assemblyName = _
                      handlerNode.Attributes.GetNamedItem("assembly").Value
                    errorHandler = _
                      handlerNode.Attributes.GetNamedItem("name").Value
                Next
                excepInfo.HandlerAssembly = assemblyName
                excepInfo.HandlerName = errorHandler
                exceptionsList.Add(exceptionName, excepInfo)
            Next
            _HandlerBucket.Add(appName, exceptionsList)
        Next
        Return _HandlerBucket
    End Function


    ' This method is called in all the catch blocks of your application
    ' It returns a URL back to the calling application
    Public Shared Function PublishException(ByVal appName As String, _
                                         ByVal e As Exception) As String
      If (appName Is Nothing) Then
          appName = "GenericAppication"
      End If


      Dim expName As String = e.GetType.ToString
      ' Read the congiuration hashtable 
      Dim handlerBucket As Hashtable = _
      CType(System.Configuration.ConfigurationSettings.GetConfig("exceptionManagers"),_
       Hashtable)

      'Find , is an appropriate handler is available for 
      'the application that raised exception
       Dim exceptionHT As Hashtable = _
           CType(handlerBucket.Item(appName), Hashtable)

      Dim excepInfo As ExceptionInfo
      If Not (exceptionHT Is Nothing) Then
          ' If application hashtable is not empty,
          ' then find the raised exception by name 
          excepInfo = CType(exceptionHT.Item(expName), ExceptionInfo)

          Dim assemName, className As String
          Dim classType As Type
          Try

            ' Load the Assembly 
              assemName = excepInfo.HandlerAssembly
              className = assemName & "." & excepInfo.HandlerName
              Dim assem As [Assembly] = [Assembly].Load(assemName)

            ' Load the handler class 
              classType = assem.GetType(className)
              Dim objref As Object = Activator.CreateInstance(classType)

            ' Cast the object to its interface, so that all exceptions
            ' can be published by a single call
            ' i have used command pattern here 
              Dim handler As IExceptionHandler = _
                  CType(objref, IExceptionHandler)
              handler.executeHandler(e)
          Catch exp As Exception
              throw new Exception ("Unknown Exception Occured " & _
                 "in loading or instantiating handler" & exp.Message)
          End Try
      End If
      Return excepInfo.RedirectUrl
    End Function
End Class

IExcceptionHandlerExceptionInfo类的代码

' IExceptionHandler Interface 
Public Interface IExceptionHandler
    Sub executeHandler(ByVal except As Exception)
End Interface

'ExceptionInfo class , that is populated with the information in the web.config

Public Class ExceptionInfo
    'Mandatory Fields
    Private _ExceptionName As String
    Private _RedirectUrl As String
    Private _ApplicationName As String
    'Optional Fields 
    Private _HandlerName As String
    Private _HandlerAssembly As String

    Public Sub New(ByVal applicationName As String, ByVal _
               exceptionName As String, ByVal errorUrl As String)
        _ApplicationName = applicationName
        _ExceptionName = exceptionName
        _RedirectUrl = errorUrl
    End Sub

    Public ReadOnly Property ExceptionName() As String
        Get
            Return _ExceptionName
        End Get
    End Property

    Public ReadOnly Property RedirectUrl() As String
        Get
            Return _RedirectUrl
        End Get
    End Property

    Public ReadOnly Property ApplicationName() As String
        Get
            Return _ApplicationName
        End Get
    End Property
    Public Property HandlerName() As String
        Get
            Return _HandlerName
        End Get
        Set(ByVal Value As String)
            _HandlerName = Value
        End Set
    End Property
    Public Property HandlerAssembly() As String
        Get
            Return _HandlerAssembly
        End Get
        Set(ByVal Value As String)
            _HandlerAssembly = Value
        End Set
    End Property
End Class

结论

以这种方式处理异常使用户能够在 Catch 块之外编写异常处理代码,因此,如果您想更改处理异常的方式,您不必深入到您的应用程序的代码中,只需编写一个新的处理程序或修改以前的那个,它将可供您的应用程序使用(前提是相应属性已相应更新)。 此外,它使您能够定义和引发您自己的异常,并以独立的方式编写其处理程序。 您还可以配置特定于应用程序的处理程序,或者您可以简单地编写一个通用处理程序,以类似的方式处理多个异常。

关注点

我使用“命令模式”和反射来实现一种独立于应用程序使用的异常处理机制。 我确实觉得玩模式很有趣,尽管我对它们了解的还很少。

© . All rights reserved.