How to Determine Exception Subtype - vb.net

I'm wondering if there's a standard way to determine the sub-type of an exception. For example, for the File.Copy() method, IOException indicates that the destination file exists OR a general I/O error occurred. There are other such cases. In my exception handler, how can I determine which it is? I'm checking the end of ex.Message for the string already exists., which works, but seems awfully kludgy and unreliable.
While it is possible to check File.Exists() on the destination file, confirm overwrite with the user if it exists and then perform File.Copy() this is not atomic, which is to say, between checking and copying, it is possible for the conditions to change, for example if some other process created or copied a file into the destination location.
EDIT:
I had already changed the code based on comments here, but I just rolled it back and will post it here, just to show what I was doing:
Try
File.Copy(SrcFile, DstFile, OverWrite)
Catch ex As DirectoryNotFoundException
MsgBox(ex.Message)
Catch ex As FileNotFoundException
MsgBox("File not found: " & ex.FileName)
Catch ex As UnauthorizedAccessException
MsgBox("You do not have write access to the destination.")
Catch ex As IOException
' IOException represents an existing destination file OR a general IO error.
If SubStr(ex.Message, -15) = "already exists." Then
OverwriteCheck = MsgBox(
"Overwrite " & IO.Path.GetFileName(SrcFile) & " in destination directory?",
MsgBoxStyle.YesNo
)
If OverwriteCheck = DialogResult.Yes Then
Try
File.Copy(SrcFile, DstFile, OverWrite)
Catch iex As Exception
MsgBox("Unable to copy " & SrcFile & ":" & vbNewLine & iex.Message)
End Try
End If
Else
Throw ex
End If
Catch ex As ArgumentException
' The user left a blank line in the text box. Just skip it.
End Try

Here is an option using FileStreams to get more granular information about your exception
Sub Main()
Try
copyTo("C:\t\output3.txt", "C:\t\output1.txt", True)
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
Console.ReadLine()
End Sub
Private Sub copyTo(source As String, destination As String, Optional overwrite As Boolean = False)
' raises FileNotFoundException if source doesn't exist
Using fsSource As New FileStream(source, FileMode.Open, FileAccess.Read, FileShare.None)
If Not overwrite AndAlso File.Exists(destination) Then
' Raises exception when destination file exists and not overwrite
Throw New Exception(
String.Format("Destination file '{0}' exists and overwrite is false.", destination))
Else
Using fsDestination As New FileStream(destination, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
fsSource.CopyTo(fsDestination)
End Using
End If
End Using
End Sub
This is a rudimentary example, but you can see how you can differentiate different exception cases, while having atomicity between checking file existence and copying.

I believe you looking for this pattern:
Try
IO.File.Copy("source", "Dest", True)
Catch exUnAuth As System.UnauthorizedAccessException
Catch exArg As System.ArgumentException
Catch exNotFound As IO.FileNotFoundException
Catch exGeneral As System.Exception
End Try
Place the list of specific exceptions first in the sequence. The last exception tested for should be the least derived.
You should read through the documentation: How to use structured exception handling in Visual Basic .NET or in Visual Basic 2005. Yes this is an old reference, but that is an indication how long this has been part of the language.

Related

Download multiple files one by one as listed in a datagridview (vb.net code)

Vb.net studio is comparivily new to (as a hobby when I have time) me so I need some help. to simply download a single file is easy I do that by the following code.
Try
' Make a WebClient.
Dim web_client As WebClient = New WebClient
' Download the file.
web_client.DownloadFile("TargetURLSite/MyFolder/" & "MyFile.exe", (Application.StartupPath & "\Plugins\" & MyFile.exe))
Catch ex As Exception
MessageBox.Show(ex.Message, "Download Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Try
Easy-Peazy...
But I now have a DataGridView column with file names of files I want to download. I thought that I could use a for each statement get the target file name from the first column of the DataGridView and execute the download function for each of the target files one by one but it dosnt seem to work I am lead to belive that its because the web client is stumbeling over its self still processing each download before being able to continue with the next.
For rowIndex = 0 To DataGridView1.RowCount - 1
'MsgBox("This cell is " & (DataGridView1.Rows(rowIndex).Cells("AppCol").Value.ToString))
Dim TargetApplication As String = (DataGridView1.Rows(rowIndex).Cells("AppCol").Value.ToString)
If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Plugins\" & TargetApplication) Then
'File exists do nothing...
Else
'File dose not exist download to Plugins directory...
Try
' Make a WebClient.
Dim web_client As WebClient = New WebClient
' Download the file.
web_client.DownloadFile("TargetURLSite/MyFolder/" & TargetApplication, (Application.StartupPath & "\Plugins\" & TargetApplication))
Catch ex As Exception
MessageBox.Show(ex.Message, "Download Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Try
End If
Next
How do I fix this? I have a limited understanding of vb.net.

Setting a textbox property value within a catch block

Using VS 2013 VB.net for my ClickOnce application. I've got a function which verifies database functionality and the guts are wrapped in a Try Catch. A portion of my Catch block looks like this:
Catch ex As Exception When Err.Number = "5"
My.Application.Log.WriteException(ex)
If My.Settings.g_blnDebugMode Then
MessageBox.Show(Err.Number & " " & ex.ToString, "Exception Error")
End If
If Err.Description.Contains("The specified table does not exist") Then
MessageBox.Show("Selected file is not a valid database.", "Exception Error")
ElseIf Err.Description.Contains("The specified password does not match the database password.") Then
MessageBox.Show("The specified password does not match the current database password.", "Exception Error")
End If
Return False
What I want to do is, clear two different fields based on the two custom error messages at the bottom. Something like TextBox1.Text = "" or TextBox2.Text = "" depending on which error is thrown (invalid password or invalid database). My problem is that I don't seem to be able to set them directly or set the value of a module or global variable from within the catch block.
Error is:
Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.
If it's possible how can I work around this and set my TextBoxes based on the results in the Catch block?
Usually the method to achieve what you are trying is to use a second a catch block
Catch ex As Exception When Err.Number = ""
MessageBox.Show(ex.Message)
FlushTextBox1();
Catch ex As Exception When Err.Number = ""
MessageBox.Show(ex.Message)
FlushTextBox2();
The error is likely appearing because the try-catch block is inside a Shared method. What that means is, the change in the value of TextBox will be repeated for all instances of the class. If you want the TextBox to behave like this, add the Shared keyword to its own declaration and remove it from the Sub's declaration. If you don't want this behaviour at all, just remove the Shared keyword. For more information on the error check the MSDN article
Alternatively you can call a local function (as shown in code) FlushTextBox1() to change the value of the TextBox outside the Sub.

Safe copy file in visual basic

The following code, was ripped out from a C# code. I wonder what is the importance of For.... To ...statement within the code?
Public Sub CopyFile(sourceFile As String, backupFile As String, overwrite As Boolean)
If String.IsNullOrEmpty(sourceFile) Then
Throw New ArgumentNullException("sourceFile")
End If
If String.IsNullOrEmpty(backupFile) Then
Throw New ArgumentNullException("backupFile")
End If
' According to MSDN Certain file attributes, Hidden and ReadOnly, can be combined. Other attributes, such as Normal, must be used alone.
If File.Exists(backupFile) Then
File.SetAttributes(backupFile, FileAttributes.Normal)
End If
' ????????
For index As Integer = 0 To 9
Try
File.Copy(sourceFile, backupFile, overwrite)
Exit Try
Catch ex As FileNotFoundException
Throw
Catch ex As Exception
If Not overwrite Then
Throw
End If
If index = 9 Then
Throw
End If
Thread.Sleep(1000)
End Try
Next
End Sub

Process Start and Errors from Slow Applications

I made an application that our company uses to launch databases and updates them on the users machine, when needed.
I am having a slight problem when it comes to launching databases and the database starts up slow. When this occurs my application throws an exception, as I assuming its awaiting some kind of response back.
As of now the error thrown is: The system cannot find the file specified
I am trying to prevent this exception logging for cases like this(Slow Application), but still allow the logging if a real error occurs while opening a database.
Current Code I am using:
Private Sub OpenApplication()
If File.Exists(LocalPathString) Then ' File Found. Open the File.
Try
Dim ps As New Process
ps = Process.Start(LocalPathString)
Catch ex As Exception
ex.Source += " | " & LocalPathString
RaiseEvent ShowError(ex)
Finally
RaiseEvent CancelIt() ' Thread Complete. Close the ActionForm
End Try
Else
If LocalPathString = vbNullString Then
RaiseEvent CancelIt() ' No file exits. Cancel thread.
Else
RaiseEvent ShowError(New Exception("Database Not Located: " & LocalPathString))
End If
End If
End Sub
StackTrace:
System.Diagnostics.Process.StartWithShellExecuteEx(startInfo As ProcessStartInfo)
App.exe: N 00912
System.Diagnostics.Process.Start()
App.exe: N 00136
System.Diagnostics.Process.Start(startInfo As ProcessStartInfo)
App.exe: N 00049
SAMi.ActionClass.OpenApplication()
App.exe: N 00117
Maybe I'm missing something, but why don't you simply omit the logging if you found that specific exception?
Catch ex As Exception
ex.Source += " | " & LocalPathString
if not ex.Message.Contains("The system cannot find the file specified") Then
RaiseEvent ShowError(ex)
end if

How to continue insert if one row fails

I have a while loop where it fetches record from csv and inserts to sql table. Now csv may contain many rows.
What I want is if one row fails just log to a file and continue with next record. I was thinking of try and catch but that will exit the program. So, any suggestions?
while (csv.readnextline)
'assign csv columns to objects
try
'insert to db
Catch ex As Exception
'write to log file
End Try
I need the above code to continue after catching an exception.
Thanks
Try and catch do not exit the program, they just control the flow of the code in case something exceptional happens.
When an exception happens in the try block, the execution continues on the first line of the (corresponding) catch block. After the execution of the catch block, the code continues on the first line after the catch, which in your case could be the End While which will continue the loop.
So an construction like this
While dr.Read
Try
InsertRowIntoDataBase()
Catch ex As Exception
LogErrorToFile(ex)
End Try
End While
should work for you.
However, this is a bad design, as it will generate and log an exception, no matter what the problem is, whether the data is invalid, or the sql server is down, or even if there is an error in your code (e.g. some lurking NullReferenceException). You should limit the handling of exception to a specific case, e.g. to a problem with the database, like this:
While dr.Read
Try
InsertRowIntoDataBase()
Catch ex As SqlClient.SqlException
LogDataBaseErrorToFile(ex)
End Try
End While
Also, if there are known possible problems with the data (e.g. a string in the csv where an integer is expected) it's better to just check that than to use an exception mechanism, something along these lines:
While dr.Read
Try
If Not IsRowValid() Then
LogInvalidDataToFile()
Continue While
End If
InsertRowIntoDataBase()
Catch ex As SqlClient.SqlException
LogDataBaseErrorToFile()
Catch ex As Exception
LogGenericErrorToFile()
End Try
End While
no it won't exit the program, depending on how/where you handle the exception. If you do something like :
Dim WrongValuedLinesList As New List(Of String)
Dim ConversionFailedList As New List(Of String)
Dim InsertionFailedList As New List(Of String)
Dim NumberOfInsertedLines As integer = 0
For Each (CurrentLine in my csv)
' 1. line processing
Try
' (process my line : split, convert, check range...)
If (I know the insertion will fail) Then
' (Store information about that wrong line, in List, log, or do nothing)
WrongValuedLinesList.Add(" This line : " & CurrentLine
& " has wrong values because...
Continue For
End If
Catch ex as exception
' (here handle the line conversion failed : store in list, or log, or do nothing ...)
' for expl :
ConversionFailedList.Add(" Conversion failed for line " & CurrentLine
& " exception details : " & ex.message " )
End Try
' 2. Line insertion
Try
'(insert my processed data into database)
NumberOfInsertedLines +=1
Catch ex as exception
' (here handle the insertion failed exception (expl : primary key might not be unique)
' : store in list, log, do nothing...)
' for example :
InsertionFailedList.Add(" Insertion failed for line " & CurrentLine
& " exception details : " & ex.message " )
End Try
Next
(Here you might wanna report how things went to your user using
your error list.)