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

使用 Web.config 配置异常

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.25/5 (4投票s)

2004年4月21日

3分钟阅读

viewsIcon

49857

downloadIcon

395

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

引言

在大型企业环境中处理异常一直是个难题,您希望以不同的方式处理不同的异常。虽然可以在 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 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.