使用 Web.config 配置异常






3.50/5 (4投票s)
2004年4月23日
3分钟阅读

59974

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
IExcceptionHandler
和ExceptionInfo
类的代码
' 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
块之外编写异常处理代码,因此,如果您想更改处理异常的方式,您不必深入到您的应用程序的代码中,只需编写一个新的处理程序或修改以前的那个,它将可供您的应用程序使用(前提是相应属性已相应更新)。 此外,它使您能够定义和引发您自己的异常,并以独立的方式编写其处理程序。 您还可以配置特定于应用程序的处理程序,或者您可以简单地编写一个通用处理程序,以类似的方式处理多个异常。
关注点
我使用“命令模式”和反射来实现一种独立于应用程序使用的异常处理机制。 我确实觉得玩模式很有趣,尽管我对它们了解的还很少。