locked
N-Layer Error Handling RRS feed

  • Question

  • User-1251405508 posted

    Im working on an N-Layer application, in which I am currently starting the data access layer.

    I am starting a base class in which my repository classes will inherit from.

    Should the base class, or the repository class be catching the exceptions and throwing a new custom application exception?

    Am I on the right track with this?

    Imports System.Data.SqlClient
    Imports System.Runtime.Serialization
    
    Public MustInherit Class SQLBase
    
        Private Function CreateConnection() As SqlConnection
            Using conn As New SqlConnection
                conn.ConnectionString = "read from application settings"
                Return conn
            End Using
        End Function
    
        Private Sub OpenConnection(ByVal conn As SqlConnection)
            Try
                conn.Open()
            Catch ex As SqlException
                Throw New CSException("A connection to the database could not be made.", _
                                      "Could not connect to the database", _
                                      "Nothing has been affected.", _
                                      "Try again", _
                                      "support@whatever.com", _
                                      ex)
    
            End Try
        End Sub
    
        Protected Function ExecuteNonQuery(ByVal sprocName As String, ByVal ParamArray sprocParams As SqlParameter()) As Integer
            Dim retval As Integer
            Using cmd As New SqlCommand
                Try
                    With cmd
                        .CommandType = CommandType.StoredProcedure
                        .CommandText = sprocName
                        .Connection = CreateConnection()
    
                        If sprocParams IsNot Nothing Then
                            For index As Integer = 0 To sprocParams.Length - 1
                                .Parameters.Add(sprocParams(index))
                            Next
                        End If
                    End With
    
                    OpenConnection(cmd.Connection)
    
                    retval = cmd.ExecuteNonQuery()
                Finally
                    'clean up
                    cmd.Connection.Close()
                End Try
            End Using
            Return retval
        End Function
    End Class
    
    
    Public Class AccountRepository : Inherits SQLBase
    
        Public Function ChangePassword(ByVal ID As Integer, ByVal Password As String) As Boolean
            Dim retval As Integer
    
    
            Try
                retval = ExecuteNonQuery("ChangePassword", _
                                         New SqlParameter("@ID", ID), _
                                         New SqlParameter("@Password", Password))
    
            Catch sqlex As SqlException
                Throw New CSException("Error Changing Password", _
                                      "An error happened while changing your password", _
                                      "Your password will not be changed", _
                                      "Validate your input and try again, if problem presists call tech support", _
                                      "Call tech support", _
                                      sqlex)
            End Try
        End Function
    
    End Class
    
    
    'Custom Application Exception
    Public Class CSException : Inherits ApplicationException
    
    #Region "Private Attributes"
        Private m_WhatHappened As String
        Private m_WhatsBeenAffected As String
        Private m_WhatCanUserDo As String
        Private m_SupportInfo As String
    #End Region
    
    #Region "Public Attributes"
        Public ReadOnly Property WhatHappened() As String
            Get
                Return m_WhatHappened
            End Get
        End Property
    
        Public ReadOnly Property WhatsAffected() As String
            Get
                Return m_WhatsBeenAffected
            End Get
        End Property
    
        Public ReadOnly Property WhatCanUserDo() As String
            Get
                Return m_WhatCanUserDo
            End Get
        End Property
    
        Public ReadOnly Property SupportInfo() As String
            Get
                Return m_SupportInfo
            End Get
        End Property
    #End Region
    
    #Region "Constructors"
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(ByVal Message As String)
            MyBase.New(Message)
        End Sub
    
        Public Sub New(ByVal Message As String, ByVal WhatHappened As String, ByVal WhatsAffected As String, ByVal WhatCanUserDo As String, ByVal SupportInfo As String, ByVal InnerException As Exception)
            MyBase.New(Message, InnerException)
            m_WhatHappened = WhatHappened
            m_WhatsBeenAffected = WhatsAffected
            m_WhatCanUserDo = WhatCanUserDo
            m_SupportInfo = SupportInfo
        End Sub
    
        Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            MyBase.New(info, context)
            m_WhatHappened = info.GetString("WhatHappened")
            m_WhatsBeenAffected = info.GetString("WhatsBeenAffected")
            m_WhatCanUserDo = info.GetString("WhatCanUserDo")
            m_SupportInfo = info.GetString("SupportInfo")
        End Sub
    
    #End Region
    
        Public Overloads Overrides Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            info.AddValue("WhatsBeenAffected", m_WhatsBeenAffected, GetType([String]))
            info.AddValue("WhatCanUserDo", m_WhatCanUserDo, GetType([String]))
            info.AddValue("SupportInfo", m_SupportInfo, GetType([String]))
            info.AddValue("WhatHappened", m_WhatHappened, GetType([String]))
            MyBase.GetObjectData(info, context)
        End Sub
    
    End Class


     

    Does anyone have any suggestions that could be made to the above code?

    Ive been struggling with this for the past few days so any help would be greatly appreciated.

    Thanks

    p.s.  what happened to the code formatting? no syntax highlighting any more?

    Monday, March 15, 2010 7:13 PM

Answers

  • User-1237044210 posted

    Hi intertek,

    Why don't you build a factory for Database connection? You built the abstract class for SQLBase is good. But what happen if I change other DBMS. And other I think you should use one IOC container for injecting any instance that you want to use. And your repository maybe lack some CRUD action for it. As far as I know, in this application you use store-procedure for perform all action on SQL server. So how do you can test store-proc if you don't have CRUD action for preparing data for test. That is my opinion about your design.

    Regards

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 15, 2010 10:55 PM

All replies

  • User-1237044210 posted

    Hi intertek,

    Why don't you build a factory for Database connection? You built the abstract class for SQLBase is good. But what happen if I change other DBMS. And other I think you should use one IOC container for injecting any instance that you want to use. And your repository maybe lack some CRUD action for it. As far as I know, in this application you use store-procedure for perform all action on SQL server. So how do you can test store-proc if you don't have CRUD action for preparing data for test. That is my opinion about your design.

    Regards

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 15, 2010 10:55 PM
  • User-1237044210 posted

    Your custom error implement is good. But I saw some design, and realized some people getting error from DBMS and stored in custom exception class. If you design a architecture according to SOA, you must be log it for trace log later. And all information threw from DBMS very useful. Once again this is only my private opinion!

    Monday, March 15, 2010 11:06 PM
  • User-1251405508 posted

    Hi Thangchung,

    Thank you but Im having trouble understanding your response.

    You say "you must be log it for trace log later", are you meaning to say that I must log the exceptions? If so, I will be. In the sample code above I left out the exception logging.

    Also, I wont be changing databases later on, this is for my company and we use stricly SQL Server.

    I will build a DAL factory later for different projects but for right now just using SQL.

     

    Other than that are there any other issues you see with this implementation?

     

    Thanks again for your help, I appreciate it.

     

     

     

    Monday, March 15, 2010 11:37 PM
  • User-1237044210 posted

    Hi  intertek,

    I don't meaning that. I only point to logging any thing you guest it error at server. You can throw exception to user, but if the system administrator want to knowing all exception in system, he/she only trace log in your system. Do you write unit test in your solution, intertek ?

    Tuesday, March 16, 2010 12:23 AM
  • User-1251405508 posted

    No, there is no unit testing.

    And I still can not make sense of your reply. Sorry.

     

    Tuesday, March 16, 2010 6:01 PM
  • User-1251405508 posted

    And other I think you should use one IOC container for injecting any instance that you want to use.
     

    What is an IOC Container, can you provide an example?

    And your repository maybe lack some CRUD action for it.

    Its not finished yet, I just meerly trying to show an example of how I was using the class file.

    Wednesday, March 17, 2010 6:00 PM