Eric J
Eric J

Reputation: 247

proper exception handling in VB.NET

I've been looking around for answers to my question and I haven't been able to find much so I'm posting here in hopes that more experienced devs can enlighten me. What is the proper way to structure exception handling in a sub? Should I wrap my Try, Catch, End Try around my whole chunk of code, or is it OK to wrap a Try, Catch, End Try around one chunk in my sub, and then Try, Catch, End Try around another chunk of code in the same sub? Here's an example of what I'm asking:

Is this better?: (OPTION 1)

Try
        'check if user has selected a file
        If ListBoxPrePublish.SelectedItems.Count = 0 Then
            MessageBox.Show("Please select a file to delete.")
            Exit Sub
        End If

        'check if user has selected a Memo to publish, if so, move file to Publish folder; if user hasn't selected a Memo, move to next If statement
        If ListBoxPrePublish.SelectedItem.Contains("-M.xls") Then
            Dim resultMemo = MessageBox.Show("Are you sure you want to delete this Memo?", "", MessageBoxButtons.YesNo)
            If resultMemo = DialogResult.Yes Then
                Dim filePath As String = "W:\TOM\ERIC\Award_Letters\Excel pre_publish\"
                Dim movePath As String = "W:\TOM\ERIC\Award_Letters\Publish\"
                Dim filenm As String = ListBoxPrePublish.SelectedItem
                Dim FileToMove = filePath & filenm
                Dim MoveToLocation = movePath & filenm
                'move the file
                System.IO.File.Move(FileToMove, MoveToLocation)
                ListBoxPublished.Items.Add(ListBoxPrePublish.SelectedItem)
                ListBoxPrePublish.Items.Remove(ListBoxPrePublish.SelectedItem)
                Exit Sub
            Else
                Exit Sub
            End If
        End If



        'ask user if they're sure they want to publish selected file and corresponding files...remember, only if the selected item is not a Memo
        Dim result = MessageBox.Show("This action will publish all corresponding files for the selected student except for Memos. Memos must be deleted individually. Do you want to continue?", "", MessageBoxButtons.YesNo)
        If result = DialogResult.No Then
            Exit Sub
        Else

            If result = DialogResult.Yes Then
                'find ID for student in unapprovd accounting file, move the record to the Deleted Today file, delete record from unapproved accounting file
                Dim UnapprovedAcctFile As String = "W:\TOM\ERIC\Award_Letters\Accounting Files\Unapproved\" & StatVar.xlApp.Sheets("New Calculator Input").Range("D30").Value & ".xlsx"
                Dim ApprovedAcctFile As String = "W:\TOM\ERIC\Award_Letters\Accounting Files\Approved\" & StatVar.xlApp.Sheets("New Calculator Input").Range("D30").Value & " Import" & ".xlsx"
                Dim searchString As String = StatVar.xlApp.Sheets("Cross Checking").Range("J6").Text 'this is the ID that will be searched for in the accounting file
                Dim rng

                'make sure accounting file for school exists
                If Not IO.File.Exists(UnapprovedAcctFile) Then
                    MessageBox.Show("Could not locate the accounting file for this school. Please contact an administrator for assistance.")
                    Exit Sub
                End If

                'open accounting file and check if it's read only, if so, another user is editing it so close it and tell the user to try again in a few seconds, if it's not read only, see next comment
                StatVar.xlWBUnapprovedAcctFile = StatVar.xlApp.Workbooks.Open(UnapprovedAcctFile)
                If StatVar.xlApp.ActiveWorkbook.ReadOnly = True Then 'check if file is read only, if so close it and exit sub
                    StatVar.xlApp.ActiveWorkbook.Close(False)
                    MessageBox.Show("The system is busy. Please try again in a few seconds.")
                    Exit Sub
                End If

                'search unapproved accounting file for ID (SSN-award year example: 555555555-13) - use searchString variable above
                rng = StatVar.xlApp.ActiveWorkbook.Sheets("Sheet1").Range("BD2:BD30002").Find(searchString, , Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlWhole, Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext, False)
                'if searchString is found
                If rng IsNot Nothing Then
                    rng.EntireRow.Select() 'select the row searchString was found in
                    'check if approved accounting file for this school exists, if not, create it
                    If Not IO.File.Exists(ApprovedAcctFile) Then
                        StatVar.xlApp.Workbooks.Add()
                        StatVar.xlApp.ActiveWorkbook.SaveAs(ApprovedAcctFile)
                        StatVar.xlApp.ActiveWorkbook.Close(True)
                    End If
                    StatVar.xlWBApprovedAcctFile = StatVar.xlApp.Workbooks.Open(ApprovedAcctFile) 'open the Approved file
                    If StatVar.xlApp.ActiveWorkbook.ReadOnly = True Then 'check if the Approved file is read only, if so, close it and exit sub because it needs to be writable
                        StatVar.xlApp.ActiveWorkbook.Close(False) 'close the Approved file, don't save changes
                        StatVar.xlApp.ActiveWorkbook.Close(False) 'close unapproved accounting file, don't save changes
                        MessageBox.Show("The system is busy. Please try again in a few seconds.")
                        Exit Sub
                    End If
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.Columns("AV").NumberFormat = "@" 'format column AV of the Approved file as text so "13/14" remains formatted correctly
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.Rows("1:1").Insert(Excel.XlInsertShiftDirection.xlShiftDown) 'insert a row at the top of the Approved file
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.Rows("1:1").Value = rng.EntireRow.Value 'set the 1st row of the Approved file equal to the row selected earlier in the unapproved accounting file
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.UsedRange.RemoveDuplicates(Columns:=(56)) 'search column 56 in Approved file for duplicates and remove entire row if a duplicate ID is found
                    rng.EntireRow.Delete() 'delete row the searchString was found in from the unapproved accounting file
                    StatVar.xlApp.ActiveWorkbook.Close(True) 'close the Approved file, save changes
                    StatVar.xlApp.ActiveWorkbook.Close(True) 'close unapproved accounting file, save changes
                    'MessageBox.Show("Eureka!")
                Else
                    'if searchString is not found, close unapproved accounting file, inform user and exit sub
                    StatVar.xlApp.ActiveWorkbook.Close(False)
                    MessageBox.Show("Could not locate this record on the accounting file. Your files were not deleted.")
                    Exit Sub
                End If

                'move selected file and corresponding non-Memo files to Publish folder
                Dim filePath As String = "W:\TOM\ERIC\Award_Letters\Excel pre_publish\"
                Dim movePath As String = "W:\TOM\ERIC\Award_Letters\Publish\"
                Dim filenm As String

                'check if each item in listbox contains the string extracted from the selected item via Excel formula; listbox select event sends the filename to Excel and a formula extracts the string to find in each listbox item...look for this string
                For Each c In ListBoxPrePublish.Items
                    If c.ToString.Contains(StatVar.xlApp.Sheets("Cross Checking").Range("H6").Text) Then
                        'make sure the current listbox item in this loop is not a Memo, if it's not, move it
                        If Not c.ToString.Contains("-M.xls") Then
                            filenm = c
                            Dim FileToMove = filePath & filenm
                            Dim MoveToLocation = movePath & filenm
                            System.IO.File.Move(FileToMove, MoveToLocation)
                            ListBoxPublished.Items.Add(c) 'add files files that are being published to the published files listbox
                        End If
                    End If
                Next

                'refresh prepublish list, if user has a school selected, REMOVE all list items that don't contain the school code being generated via VLOOKUP in Excel using the school name from comboboxschool; look for this string in the loop surrounded with "-"
                Call ListFiles()
                If ComboBoxSchool.Text <> "" Then
                    For i As Integer = ListBoxPrePublish.Items.Count - 1 To 0 Step -1
                        'if current loop item does not contain the school code for the selected school, remove the item from the listbox
                        If Not ListBoxPrePublish.Items(i).Contains("-" & StatVar.xlApp.Sheets("Cross Checking").Range("E3").Text & "-") Then
                            ListBoxPrePublish.Items.RemoveAt(i)
                        End If
                    Next
                End If
                'refresh deleted files listbox
                Call ListDeletedTodayFiles()

            End If
        End If
    Catch exc As Exception
        MessageBox.Show("Unable to publish the selected file. Please verify this file or any of its corresponding files are not open by you or another user. If the problem persists, contact an administrator for assistance." & vbNewLine & vbNewLine & "Error: " & exc.Message)
    End Try

OR IS THIS BETTER?: (OPTION 2)

 Try
        'check if user has selected a file
        If ListBoxPrePublish.SelectedItems.Count = 0 Then
            MessageBox.Show("Please select a file to delete.")
            Exit Sub
        End If

        'check if user has selected a Memo to publish, if so, move file to Publish folder; if user hasn't selected a Memo, move to next If statement
        If ListBoxPrePublish.SelectedItem.Contains("-M.xls") Then
            Dim resultMemo = MessageBox.Show("Are you sure you want to delete this Memo?", "", MessageBoxButtons.YesNo)
            If resultMemo = DialogResult.Yes Then
                Dim filePath As String = "W:\TOM\ERIC\Award_Letters\Excel pre_publish\"
                Dim movePath As String = "W:\TOM\ERIC\Award_Letters\Publish\"
                Dim filenm As String = ListBoxPrePublish.SelectedItem
                Dim FileToMove = filePath & filenm
                Dim MoveToLocation = movePath & filenm
                'move the file
                System.IO.File.Move(FileToMove, MoveToLocation)
                ListBoxPublished.Items.Add(ListBoxPrePublish.SelectedItem)
                ListBoxPrePublish.Items.Remove(ListBoxPrePublish.SelectedItem)
                Exit Sub
            Else
                Exit Sub
            End If
        End If
    Catch exc As Exception
        MessageBox.Show("An error occured and the selected file was not published. Please contact an administrator if the problem continues." & vbNewLine & vbNewLine & "Error: " & exc.Message)
    End Try

    Try
        'ask user if they're sure they want to publish selected file and corresponding files...remember, only if the selected item is not a Memo
        Dim result = MessageBox.Show("This action will publish all corresponding files for the selected student except for Memos. Memos must be deleted individually. Do you want to continue?", "", MessageBoxButtons.YesNo)
        If result = DialogResult.No Then
            Exit Sub
        Else

            If result = DialogResult.Yes Then
                'find ID for student in unapprovd accounting file, move the record to the Deleted Today file, delete record from unapproved accounting file
                Dim UnapprovedAcctFile As String = "W:\TOM\ERIC\Award_Letters\Accounting Files\Unapproved\" & StatVar.xlApp.Sheets("New Calculator Input").Range("D30").Value & ".xlsx"
                Dim ApprovedAcctFile As String = "W:\TOM\ERIC\Award_Letters\Accounting Files\Approved\" & StatVar.xlApp.Sheets("New Calculator Input").Range("D30").Value & " Import" & ".xlsx"
                Dim searchString As String = StatVar.xlApp.Sheets("Cross Checking").Range("J6").Text 'this is the ID that will be searched for in the accounting file
                Dim rng

                'make sure accounting file for school exists
                If Not IO.File.Exists(UnapprovedAcctFile) Then
                    MessageBox.Show("Could not locate the accounting file for this school. Please contact an administrator for assistance.")
                    Exit Sub
                End If

                'open accounting file and check if it's read only, if so, another user is editing it so close it and tell the user to try again in a few seconds, if it's not read only, see next comment
                StatVar.xlWBUnapprovedAcctFile = StatVar.xlApp.Workbooks.Open(UnapprovedAcctFile)
                If StatVar.xlApp.ActiveWorkbook.ReadOnly = True Then 'check if file is read only, if so close it and exit sub
                    StatVar.xlApp.ActiveWorkbook.Close(False)
                    MessageBox.Show("The system is busy. Please try again in a few seconds.")
                    Exit Sub
                End If

                'search unapproved accounting file for ID (SSN-award year example: 555555555-13) - use searchString variable above
                rng = StatVar.xlApp.ActiveWorkbook.Sheets("Sheet1").Range("BD2:BD30002").Find(searchString, , Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlWhole, Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext, False)
                'if searchString is found
                If rng IsNot Nothing Then
                    rng.EntireRow.Select() 'select the row searchString was found in
                    'check if approved accounting file for this school exists, if not, create it
                    If Not IO.File.Exists(ApprovedAcctFile) Then
                        StatVar.xlApp.Workbooks.Add()
                        StatVar.xlApp.ActiveWorkbook.SaveAs(ApprovedAcctFile)
                        StatVar.xlApp.ActiveWorkbook.Close(True)
                    End If
                    StatVar.xlWBApprovedAcctFile = StatVar.xlApp.Workbooks.Open(ApprovedAcctFile) 'open the Approved file
                    If StatVar.xlApp.ActiveWorkbook.ReadOnly = True Then 'check if the Approved file is read only, if so, close it and exit sub because it needs to be writable
                        StatVar.xlApp.ActiveWorkbook.Close(False) 'close the Approved file, don't save changes
                        StatVar.xlApp.ActiveWorkbook.Close(False) 'close unapproved accounting file, don't save changes
                        MessageBox.Show("The system is busy. Please try again in a few seconds.")
                        Exit Sub
                    End If
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.Columns("AV").NumberFormat = "@" 'format column AV of the Approved file as text so "13/14" remains formatted correctly
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.Rows("1:1").Insert(Excel.XlInsertShiftDirection.xlShiftDown) 'insert a row at the top of the Approved file
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.Rows("1:1").Value = rng.EntireRow.Value 'set the 1st row of the Approved file equal to the row selected earlier in the unapproved accounting file
                    StatVar.xlApp.ActiveWorkbook.ActiveSheet.UsedRange.RemoveDuplicates(Columns:=(56)) 'search column 56 in Approved file for duplicates and remove entire row if a duplicate ID is found
                    rng.EntireRow.Delete() 'delete row the searchString was found in from the unapproved accounting file
                    StatVar.xlApp.ActiveWorkbook.Close(True) 'close the Approved file, save changes
                    StatVar.xlApp.ActiveWorkbook.Close(True) 'close unapproved accounting file, save changes
                    'MessageBox.Show("Eureka!")
                Else
                    'if searchString is not found, close unapproved accounting file, inform user and exit sub
                    StatVar.xlApp.ActiveWorkbook.Close(False)
                    MessageBox.Show("Could not locate this record on the accounting file. Your files were not deleted.")
                    Exit Sub
                End If

                'move selected file and corresponding non-Memo files to Publish folder
                Dim filePath As String = "W:\TOM\ERIC\Award_Letters\Excel pre_publish\"
                Dim movePath As String = "W:\TOM\ERIC\Award_Letters\Publish\"
                Dim filenm As String

                'check if each item in listbox contains the string extracted from the selected item via Excel formula; listbox select event sends the filename to Excel and a formula extracts the string to find in each listbox item...look for this string
                For Each c In ListBoxPrePublish.Items
                    If c.ToString.Contains(StatVar.xlApp.Sheets("Cross Checking").Range("H6").Text) Then
                        'make sure the current listbox item in this loop is not a Memo, if it's not, move it
                        If Not c.ToString.Contains("-M.xls") Then
                            filenm = c
                            Dim FileToMove = filePath & filenm
                            Dim MoveToLocation = movePath & filenm
                            System.IO.File.Move(FileToMove, MoveToLocation)
                            ListBoxPublished.Items.Add(c) 'add files files that are being published to the published files listbox
                        End If
                    End If
                Next

                'refresh prepublish list, if user has a school selected, REMOVE all list items that don't contain the school code being generated via VLOOKUP in Excel using the school name from comboboxschool; look for this string in the loop surrounded with "-"
                Call ListFiles()
                If ComboBoxSchool.Text <> "" Then
                    For i As Integer = ListBoxPrePublish.Items.Count - 1 To 0 Step -1
                        'if current loop item does not contain the school code for the selected school, remove the item from the listbox
                        If Not ListBoxPrePublish.Items(i).Contains("-" & StatVar.xlApp.Sheets("Cross Checking").Range("E3").Text & "-") Then
                            ListBoxPrePublish.Items.RemoveAt(i)
                        End If
                    Next
                End If
                'refresh deleted files listbox
                Call ListDeletedTodayFiles()

            End If
        End If
    Catch exc As Exception
        MessageBox.Show("Unable to publish the selected file. Please verify this file or any of its corresponding files are not open by you or another user. If the problem persists, contact an administrator for assistance." & vbNewLine & vbNewLine & "Error: " & exc.Message)
    End Try

Are either 1 of these methods better practice than the other? Or is it up to me and will depend on what I'm doing with my procedure? Would love to hear different opinions on this.

Upvotes: 3

Views: 4219

Answers (4)

Tony Hopkinson
Tony Hopkinson

Reputation: 20330

Looks a worse problem than it is, because you could do with breaking up that method into several small ones

Look at it this way

if you had a, b and c and you wanted to work out a / b and a / c and you put all that in one try catch for a div by zero exception, you'd have to more work to figure out whether b or c was the bad guy, two try catch blocks you would know.

Yes I know this isn't the best example of when to use exceptions, but the answer to your question, is it depends on how you want to handle known exceptions from a segment of code.

In the above if you were ok with your handle being "Either b or c is zero" , then one block is the solution.

Upvotes: 1

Kees
Kees

Reputation: 1418

You should try to handle exceptions in a global way like on application event level. If you want other code to continue you should make the blocks as narrow as possible. Catching exceptions will affect performance.

Upvotes: 1

user2588578
user2588578

Reputation: 58

It is wise to wrap try catch around smaller chunk of code, depending on what depth of error handling you want to perform. Microsoft has a page on Best Practices for error handling:

MSDN Best Practices for Handling Exceptions

Upvotes: 3

Karl Anderson
Karl Anderson

Reputation: 34834

Wrap your Try-Catch-Finally blocks around smaller portions of code, as then you will have a better chance of more quickly finding the error and also potentially recover from the exception and continue on with part of your logic. In your one exception handler scenario, if any error happens, then the rest of the logic is not executed, it also makes for finding where the error happened much more difficult. This brings up the final recommendation, make your method do less; methods where you need to scroll multiple pages are doing too much and are very difficult to understand and maintain and almost assuredly impossible to reuse anywhere else.

You should also not just use the base Exception as this is a catch-all type of exception and provides no insight into what type of more specific exception actually happened.

Upvotes: 5

Related Questions