Configuring Exceptions Using Web.config

24923 단어 exception

Introduction


It's always been a problem to handle exceptions in a large enterprise environment, where you want to deal with different exceptions in a different manner. Though error pages can be configured in the web.config, but for only HTTP specific errors. You cannot define specific Exception types with their respective handlers. One of the solutions that I found on the net was Exceptions Management Block . But that was after all a complex solution according to me. So I devised my own mechanism to configure Exception types with their respective handlers in web.config.

Problem Definition


Normally, in a simple application, we deal with exceptions in a Try - Catch block like this:
    Try 
        // Do some code here
    Catch sqle as SQLExceptions 
        // Handle SQLException differently
    Catch e as Exceptions 
        // Handle Generic Exception differently
    End Try

This is fine up to a simple application, but for an enterprise application where several pages can raise exceptions, it can cause a headache to configure each of these blocks individually. Also, if you have derived your own application specific exceptions, you have to handle them separately, and if you want to make any change in handling exceptions, you have to dive into your aspx pages.

Proposed Solution


To overcome this problem, I have defined a custom configuration section, that defines exception type, with its ErrorHandler (assembly and class) and RedirectURL. In this way, you can configure an exception, its handler (both assembly and class) and redirect URL without intervening into your previously written code, in an independent manner.

Configuring And Handling Exceptions


First of all, we have to define a custom configuration section in web.config, just below <configuration> tag.
    <configSections >
        <section name="exceptionManagers" 
          type="ExceptionManagers.ExceptionManagersHandler,ExceptionManagers" />
     </configSections>

And just before ending <configuration> tag , write this:
<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>

The above section defines an exception of type System.SQLException , that if raised in application "MyApplication", will be handled by SQLExceptionHandler class from ExceptionManagers assembly, and after handling, it will be redirected to ErrorPage.aspx. You can define all other exceptions you want to handle by replicating <ExceptionManager> tag, and setting its attributes. By defining handlers in this way, we can isolate our Exception handling logic from being written into the code (Try - Catch blocks). What we have to do is to just put a single line in our Try - Catch block, which is written below:
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

This line simply calls a shared method PublicshException of the class ExceptionManagersHandler and passes it the name of the application that raised this exception and the exception object itself.

Using the code


To define the exception handlers, create a class library project and name it ExceptionManagers (which is the assembly name in ExceptionHandler tag). Now, add a class SQLExceptionHandler to handle the SQLException . This class implements IExceptionHandler , an interface that defines a single executeHandler method. When an exception of type SQLException is raised, and ExceptionManager.PublishException is called, it retrieves the configuration settings from the web.config and searches for an appropriate handler of the exception. The method then uses Reflection namespace to instantiate a handler and delegates a call to it. The code for the said classes is below:
' 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

The code for IExcceptionHandler and ExceptionInfo class:
' 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

Conclusion


Handling exceptions in such way gives a user ability to write the exception handling code outside the catch block, so that if you want to change the way exception is handled, you don't have to dive in your application's code, just write a new handler aur modify the earlier one, and it will be available to your application (provided that concerned attributes are updated accordingly). Also, it enables you to define and raise your own exceptions and write their handlers in an independent manner. You can also configure application specific handlers or you can simply write a generic handler to handle multiple exceptions in a similar manner.

Points of Interest


I used Command Pattern with reflection to implement an exception handling mechanism that is independent of the using application. I do feel fun to play with patterns, though I know much less about them :).

About M. Furqan Hameedi


I am an IT graduate , and have secured SCPJ 2 and IBM XML developer cerifications.Started my career as J2EE developer, but now focused on .Net technologies.Currently working as a web developer ,in infinilogic (www.infinilogic.com),a UK based organization , providing business solutions. Click here to view M. Furqan Hameedi's online profile.

Other popular articles:

  • Applying Robustness Analysis on the Model–View–Controller (MVC) Architecture in ASP.NET Framework, using UML This article will enhance your vision on the usage of Robustness Analysis in conjunction with Model View Controller, using UML with application in ASP.NET. This article is a sequel to my articles on Architecture and Design with ASP.NET.
  • MasterPages reinvented - a Component Based Template Engine for ASP.NET User-friendly but powerful template engine which provides clean and painless separation of content and MasterPages (templates).
  • NoSpamEmailHyperlink: 4. Design-Time Functionality Adding full design time functionality to your custom control in a few easy steps.
  • SqlWhereBuilder ASP.NET Server Control A user interface web control for building conditions suitable for use in a SQL statement.
  • 원문 주소:
    http://www.codeproject.com/aspnet/Exception_Handling.asp

    좋은 웹페이지 즐겨찾기