Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Custom Exception Framework: Using Enterprise Library Exception Handling Block

3.95/5 (16 votes)
30 Oct 2008CPOL3 min read 2   1.1K  
This article demonstrates a working model of a custom Exception block using Enterprise Library Exception Handling Block which is built around MVP architecture.

Introduction

This article demonstrates the creation of a custom Exception Layer using the Microsoft Enterprise Library Exception Handling block. The demo created in this article has a Model View Presenter architecture with a custom exception layer built in it.

System Requirement

  • Install Microsoft Enterprise Library .NET 2.0
  • .NET Framework 2.0

Important Namespaces

Microsoft.Practices.EnterpriseLibrary.ExceptionHandling

  • Microsoft.Practices.EnterpriseLibrary.Common.dll
  • Microsoft.Practices.ObjectBuilder.dll
  • Microsoft.Practices.EnterpriseLibrary.Common.dll
  • System.Collections.Specialized.dll
  • System.Configuration.Assemblies.dll

Features of the Custom Exception Block

  1. The custom block partitions exceptions based on layers. E.g. Data Access Layer Exception, Presenter Layer Exception, Service Layer Exception, and so on.
  2. This custom Exception also targets system layer exceptions like Critical Exception. For example: When the database server is down, or a Web Service is unavailable, and so on.
  3. This custom exception also addresses exceptions that are handled and custom messages to be shown to the user. For example, insert duplicate records in database, exception thrown from database, and this handled in a .NET application and bubbled up to show a user defined warning message. So this eventually separates the warnings, errors, and exceptions. For an unhandled system error, the system is redirected to an error page. For a warning or operational information, it is shown on the same functional screen so that normal execution is not stopped.
  4. This block is integrated with Model View Presenter Architecture.

Configuration Setting

The configuration settings encapsulate the various policies required for the application. The policies are:

  1. Global Policy: Identifies the actual exception that comes from the layers.
  2. Propagate Policy: This policy propagates the actual exception thrown from layers to the mainstream.
  3. Custom Policy: Presenter/Data Access/View/Service.
PolicyPost Handling ActionLayer
1GlobalNoneProject.Practice.MVP.ExceptionHandling
2PropagateNotifyReThrowSystem.Exception
3Custom: Presenter LayerThrowNewExceptionProject.Practice.MVP.Presenter
4Custom: Data Access LayerThrowNewExceptionProject.Practice.MVP.DataAccess
5Custom: View LayerThrowNewExceptionProject.Practice.MVP.Web

Image 1

Image 2

Configuration

Image 4

Image 5

Image 6

Project.Practice.MVP.ExceptionHandling: Custom Exception Class

The physical representation of the exception handling class with the MVP model is as shown below.

Configuration

The below class diagram depicts the picture of the exception handling class construct. All the layers of custom exception classes are created. These classes in turn inherit the BaseException class.

Configuration

Project.Practice.MVP.ExceptionHandling: ApplicationExceptionHandler.cs

In this class, we have a method called HandleException which implements the interface method IExceptionHandler.

C#
namespace Project.Practice.MVP.ExceptionHandling
{
    [ConfigurationElementType(typeof(CustomHandlerData))]
    public class ApplicationExceptionHandler : IExceptionHandler
    {
        private const string UNEXPECTED_ERROR = "Unexpected Error!!";
        public ApplicationExceptionHandler(NameValueCollection ignore)
        {

        }
        #region IExceptionHandler Members
        public Exception HandleException(Exception exception, 
                                         Guid correlationID)
        {
            try
            {
                /* This is Critical Layer Exception.
                For E.g Database Unavailable
                Web Service Unavailable and so on .*/
               
                if (exception.GetType().Equals(
                      typeof(CustomException.CriticalException)))
                {
                    if (HttpContext.Current.Items.Contains("ERROR_MSG"))
                    {
                        HttpContext.Current.Items.Remove("ERROR_MSG");
                    }
                    HttpContext.Current.Items.Add("ERROR_MSG", exception.Message);
                    HttpContext.Current.Server.Transfer(
                                "~/CriticalException.aspx", false);
                }    
                //This is Presenter Layer Exception.
                else if (exception.GetType().Equals(
                          typeof(CustomException.PresenterLayerException)))
                {

                    if ((CustomPage)HttpContext.Current.Handler != null)
                    {
                        ((CustomPage)HttpContext.Current.Handler).Error = 
                            "Presenter Layer Exception :" + 
                            exception.InnerException.Message ;
                    }
                }
                //This is View Layer Exception.
                else if (exception.GetType().Equals(
                          typeof(CustomException.ViewLayerException)))
                {
                    if ((CustomPage)HttpContext.Current.Handler != null)
                    {
                        ((CustomPage)HttpContext.Current.Handler).Error = 
                            "View Layer Exception:" + exception.Message;
                     }
                }
                //This is DataAccess Layer Exception
                else if (exception.GetType().Equals(
                          typeof(CustomException.DataAccesLayerException)))
                {
                    if ((CustomPage)HttpContext.Current.Handler != null)
                    {                      
                        ((CustomPage)HttpContext.Current.Handler).Error = 
                            "DataAccess Layer Exception: "+ exception.Message;
                    }
                }
                //This is SQL DAL Layer Exception
                else if (exception.GetType().Equals(
                             typeof(CustomException.SQLDALException)))
                {
                    if ((CustomPage)HttpContext.Current.Handler != null)
                    {
                        ((CustomPage)HttpContext.Current.Handler).Error = 
                            "SQL Error 101: " + exception.Message;
                    }
                }
                else
                {
                    if ((CustomPage)HttpContext.Current.Handler != null)
                    {
                       //This is Session Expired Exception
                        if ((((CustomPage)
                               HttpContext.Current.Handler).CurrentSession == null))
                        {
                            HttpContext.Current.Items["ERROR_MSG"] = "Access Denied";
                            HttpContext.Current.Server.Transfer(
                                        "~/CriticalException.aspx", false);
                        }
                        //This is General Exception:UN_DEFINED EXCEPTION
                        HttpContext.Current.Server.Transfer(
                                    "~/CriticalException.aspx", false);
                    }
                }
            }
            catch (System.Threading.ThreadAbortException ex)
            {
            }
            catch (Exception ex)
            {
            }
            return exception;
        }

        #endregion
    }
}

Project.Practice.MVP.ExceptionHandling: ExceptionHandleProvider.cs

This is called from the web pages where the exception gets bubbled up.

C#
namespace Project.Practice.MVP.ExceptionHandling
{
    public class ExceptionHandleProvider
    {
        public static bool HandleException(Exception exception, string PolicyName)
        {
            bool reThrow = false;
            reThrow = ExceptionPolicy.HandleException(exception, PolicyName);
            return reThrow;
        } 
    }
}

Project.Practice.MVP.DataAccess:DataProvider

This is a partial class. We have a partial class named 'DataProvider' with a different file name for each module. In this method, if the exception is a Critical Exception in the Data Access Layer, it will be propagated across the layer to display a Critical Exception, but if there is a DataAccess exception, then this will get propagated through the other layers to display a DataAccessLayer Exception.

C#
namespace Project.Practice.MVP.DataAccess
{
    public partial class DataProvider
    {
        public static void ProcessDataAccessLayerException(Exception ex)
        {
            bool reThrow = false;
            if (ex.GetType().Equals(typeof(CriticalException)) == true)
            {
                reThrow = ExceptionPolicy.HandleException(ex, "Propogate Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
            else if (ex.GetType().Equals(typeof(SQLDALException)) == true)
            {
                reThrow = ExceptionPolicy.HandleException(ex, "Propogate Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
            else
            {
                reThrow = ExceptionPolicy.HandleException(ex, "DataAccess Layer Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }

        } 

    }
}

Now we have a partial class DataProvider with a file module named MathOperationDataProvider.cs.

DataAccess:Raise Exception

C#
namespace Project.Practice.MVP.DataAccess
{
    public partial class DataProvider
    {
        /// <summary>
        /// Get DemandList 
        /// </summary>
        /// <returns></returns>
        public static int AddOperation(int result)
        {
            string error = "SQL_DAL_EXCEPTION";
            try
            {

                if (error == "SQL_DAL_EXCEPTION")
                { 
                    throw new SQLDALException("SQL Store Procedure Error") ;
                }
                if (error == "DATA_ACCESS_LAYER")
                {
                    throw new DataAccesLayerException("Data Not Found Error");
                }
                if (error == "CRITICAL EXCEPTION")
                {
                    throw new CriticalException();
                }
            }
            catch(Exception ex)
            {
                ProcessDataAccessLayerException(ex);
            }
            return result;
        }       
    }
}

Project.Practice.MVP.Presenter

BasePresenter.cs

C#
namespace Project.Practice.MVP.Presenter
{
    public class BasePresenter
    {
        public IServicesProvider m_Service = null;
        public BasePresenter()
        {
            m_Service = new Services.ServicesProvider();
        }
      
        public void ProcessPresenterLayerException(Exception ex)
        {
            bool reThrow = false;
            if (ex.GetType().Equals(typeof(CriticalException)))
            {
                reThrow = ExceptionPolicy.HandleException(
                             ex, "Propogate Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
            else if (ex.GetType().Equals(typeof(ViewLayerException)))
            {
                reThrow = ExceptionPolicy.HandleException(
                           ex, "Propogate Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
            else if (ex.GetType().Equals(typeof(DataAccesLayerException)) == true)
            {
                reThrow = ExceptionPolicy.HandleException(
                             ex, "Propogate Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
            else if (ex.GetType().Equals(typeof(SQLDALException)) == true)
            {
                reThrow = ExceptionPolicy.HandleException(
                            ex, "Propogate Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
            else
            {
                reThrow = ExceptionPolicy.HandleException(
                               ex, "Presenter Layer Policy");
                if (reThrow)
                {
                    throw ex;
                }
            }
        } 

    }
}

CalculationPresenter.cs

C#
namespace Project.Practice.MVP.Presenter
{
    public class CalculationPresenter : BasePresenter
    {
        #region Public Members
        private ICalculationView m_View = null;
        #endregion

        #region Public Constructor
        public CalculationPresenter(ICalculationView view)
            : base()
        {
            m_View = view;
        }
        #endregion

      
        public void Initialize()
        {
            //Security Check
            //If(user session expires Or login user fails
            //Throw New CriticalLayerException()
        }
        public void AddNumbers()
        {
            try
            {
                m_View.Result= Convert.ToString(AddOperations());
            }
            catch (Exception ex)
            {
                ProcessPresenterLayerException(ex);
            }
        }
        private int AddOperations()
        {
            int result = m_View.Numbers1 + m_View.Numbers2;
            return m_Service.AddOperation(result);
        }
    }
}

Project.Practice.MVP.Web

C#
public partial class Calculation : CustomPage,ICalculationView
{
    #region Private Members
    private CalculationPresenter m_Presenter = null;
    #endregion
    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            m_Presenter = new CalculationPresenter((ICalculationView)this);
            if (ViewState["USER_KEY_VALUE"] == null)
            {
                throw new ViewLayerException("Code Behind Exception");
            }
        }
        catch (Exception ex)
        {
            if (ExceptionHandleProvider.HandleException(
                        ex, "Global Policy") == true)
            {
                throw ex;
            }
        }       
    }

    #region ICalculationView Members

    public int Numbers1
    {
        get
        {
            return Convert.ToInt32(txtNumber1.Text);
        }
    }

    public int Numbers2
    {
        get
        {
            return Convert.ToInt32(txtNumber2.Text);
        }
    }

    public string Result
    {
        set
        {
            lblResult.Text = value;
        }
    }

    #endregion
    protected void Button1_Click(object sender, EventArgs e)
    {
        try
        {
            m_Presenter.AddNumbers();
        }
        catch (Exception ex)
        {
            if (ExceptionHandleProvider.HandleException(
                      ex, "Global Policy") == true)
            {
                throw ex;
            }
        }      

    }

    public override string Error
    {
        set {pnlError.Visible = true;
            lblException.Text = value; ; }
    }
}

Final Show

This exception is thrown or raised from the code-behind of an ASPX page.

Configuration

C#
protected void Page_Load(object sender, EventArgs e)
{
    try
    {
        m_Presenter = new CalculationPresenter((ICalculationView)this);
        if (ViewState["USER_KEY_VALUE"] == null)
        {
            throw new ViewLayerException("Code Behind Exception");
        }
    }
    catch (Exception ex)
    {
        if (ExceptionHandleProvider.HandleException(
                   ex, "Global Policy") == true)
        {
            throw ex;
        }
    }
}

Configuration

This exception is raised from the data access layer. Just change the error variable to test this layer.

C#
string error = "DATA_ACCESS_LAYER";
try
{
    if (error == "SQL_DAL_EXCEPTION")
    { 
        throw new SQLDALException("SQL Store Procedure Not Found") ;
    }
    if (error == "DATA_ACCESS_LAYER")
    {
        throw new DataAccesLayerException("Data Not Found Error");
    }
    if (error == "CRITICAL EXCEPTION")
    {
        throw new CriticalException();
    }
}

Configuration

This is a business layer exception and it occurs in the Presenter Layer. Just enter the value as given in the screenshot.

C#
public void AddNumbers()
{
    try
    {
        m_View.Result= Convert.ToString(AddOperations());
    }
    catch (Exception ex)
    {
        ProcessPresenterLayerException(ex);
    }
}

This is how we can create a custom exception as per our requirements. The demo project requires Enterprise Library DLLs, so we need to install the Microsoft Enterprise Library to run this source code.

I have tried my best to put sufficient information here to explain the working model of custom exceptions using the Enterprise Library.

Reference

Built the Exception Handling Block using this UI Interface: Enterprise Library ExceptionHandling Block.

Model View Presenter: MVP Architecture.

Conclusion

Any corrections, criticisms, and advise are most welcome.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)