For example when there is multiple exception I need to handle, below way takes more space.
Is there a shorter way to Try Catch ex As Exception in single line VB.NET? maybe something like Try objSize = obj.Size Catch ex As Exception objSize = 0
Also if anyone can share best practices for error handling in vb.net it'd be much appreciated. Thanks.
Try
objSize = obj.Size
Catch ex As Exception
objSize = 0
End Try
There's a very good discourse in the comments on the question here and everyone raised valid points.
The only way that code will throw an exception is if retrieving the object size throws an exception. The only thing you do if it throws an exception is set the size to 0. Ergo, you should just make object.Size return 0 if it was going to throw an exception. No throwing needless exceptions is a best practice because they're expensive.
You can, however declare a sub that takes other subs as parameters:
Sub TryCatch(t as Action, c as Action)
Try
t()
Catch
c()
End try
End Sub
And then capture your lines of code that you formerly trycatched, as subs:
Dim objSize = 0
TryCatch(Sub() objSize = obj.Size, Sub() objSize = 0)
Or you can use c# ;)
Here is an example of one line Try .. Catch
Try : objSize = obj.Size : Catch ex As Exception : objSize = 0 : End Try
I'm just wondering how are you going to Debug your Code, if it only
goes like that in bigger application ?!
The answer to how to do this is to not use a try catch block at all.
objSize = If(obj?.Size, 0)
Does all you need it to in this case.
If you don’t like the syntax, then there’s this
objSize =(obj?.Size).GetValueOrDefault
Either way, try catch blocks are for recovering from unknown errors, not ones that can be handled more easily with a simple change in how the code looks.
three questions please
1) If there is an exception in the try below will the request stream automatically close as it is in a using
2)do I even need the requestStream.Close() and requestStream.Dispose() as it is in a using?
3) do I need to close the System.Net.FtpWebRequest?
Try
Dim rqst As System.Net.FtpWebRequest = DirectCast(System.Net.WebRequest.Create("ftp://1.com/text.txt"), System.Net.FtpWebRequest)
rqst.Credentials = New System.Net.NetworkCredential("useb", "pass")
rqst.Method = System.Net.WebRequestMethods.Ftp.UploadFile
'Throw New ApplicationException("Exception Occured")
Dim fle() As Byte = System.IO.File.ReadAllBytes("C:\test.txt")
Using requestStream As Stream = rqst.GetRequestStream()
requestStream.Write(fle, 0, fle.Length)
requestStream.Close() 'do I need this?
requestStream.Dispose() 'do I need this ?
End Using
Catch ex As Exception
MessageBox.Show(ex.Message.ToString())
End Try
No you dont need if you are using using. As using itself is used to dispose of. Also the reason for the "using" statement is to ensure that the object is always disposed correctly, and it doesn't require explicit code to ensure that this happens.
Dispose method is called immediately when control flow exits the using block.
Yes. If the exception occurs while executing code inside the using statement, the stream will be disposed before it goes to the Catch block.
Here's the code example :
Try
Throw New FirstException()
Finally
Throw New SecondException()
End Try
I figured out it only throws SecondException out and FirstException just vanishes.
I thought FirstException would be inside InnerException property of SecondException but it appears it is not.
I'm not blocked on anything as I don't really need the FirstException to show up, I'm just rather intrigued about this behaviour.
Is there a way to know SecondException did get thrown first when
catching it all at upper level ?
If the first exception really is overriden by the second, what is the
reason ?
Does it happen in every other language ? Is it logical ?
I guess the primary explanation for why this works this way is that you are never catching your first exception and passing it along the chain. If you have a situation like the above where you may be throwing several exceptions on the way back to the original caller then you have to either catch them as they are thrown (and include them as an inner exception when creating the next one) :
Dim ex1 As Exception = Nothing
Try
Throw New Exception("first exception")
Catch ex As Exception
ex1 = ex
Finally
Throw New Exception("second exception", ex1)
End Try
Or, probably better - just don't throw until you have all of the exceptions figured out:
Dim ex1 As Exception = Nothing
Try
ex1 = New Exception("first exception")
Finally
Throw New Exception("second exception", ex1)
End Try
Throwing and catching exceptions is expensive, so it's probably best to not throw until you're ready to return and just log along the way.
One of the limitations of exception handling in .net is that there is no nice way for code in a Finally block to know what exception, if any, caused the code in the Try block to exit, nor is there any normal way for code in a finally block which does have such information to make it available to code which might throw an exception.
In vb.net, it's possible to kludge things in a manner that works pretty well, even though it looks a bit ugly.
Module ExceptionDemo
Function CopySecondArgToFirstAndReturnFalse(Of T)(ByRef dest As T, src As T) As Boolean
dest = src
Return False
End Function
Function AnnotateExceptionAndReturnFalse(ex As Exception, TryBlockException As Exception) As Boolean
If ex Is Nothing Then Return False ' Should never occur
If TryBlockException Is Nothing Then Return False ' No annotation is required
ex.Data("TryBlockException") = TryBlockException
Return False
End Function
Sub ExceptionTest(MainAction As Action, CleanupAction As Action)
Dim TryBlockException As Exception = Nothing
Try
MainAction()
Catch ex As Exception When CopySecondArgToFirstAndReturnFalse(TryBlockException, ex)
' This block never executes, but above grabs a ref to any exception that occurs
Finally
Try
CleanupAction()
Catch ex As Exception When AnnotateExceptionAndReturnFalse(ex, TryBlockException)
' This block never executes, but above performs necessary annotations
End Try
End Try
End Sub
Sub ExceptionTest2(Message As String, MainAction As Action, CleanupAction As Action)
Debug.Print("Exception test: {0}", Message)
Try
ExceptionTest(MainAction, CleanupAction)
Catch ex As Exception
Dim TryBlockException As Exception = Nothing
Debug.Print("Exception occurred:{0}", ex.ToString)
If ex.Data.Contains("TryBlockException") Then TryBlockException = TryCast(ex.Data("TryBlockException"), Exception)
If TryBlockException IsNot Nothing Then Debug.Print("TryBlockException was:{0}", TryBlockException.ToString)
End Try
Debug.Print("End test: {0}", Message)
End Sub
Sub ExceptionDemo()
Dim SuccessfulAction As Action = Sub()
Debug.Print("Successful action")
End Sub
Dim SuccessfulCleanup As Action = Sub()
Debug.Print("Cleanup is successful")
End Sub
Dim ThrowingAction As Action = Sub()
Debug.Print("Throwing in action")
Throw New InvalidOperationException("Can't make two plus two equal seven")
End Sub
Dim ThrowingCleanup As Action = Sub()
Debug.Print("Throwing in cleanup")
Throw New ArgumentException("That's not an argument--that's just contradiction")
End Sub
ExceptionTest2("Non-exception case", SuccessfulAction, SuccessfulCleanup)
ExceptionTest2("Exception in main; none in cleanup", ThrowingAction, SuccessfulCleanup)
ExceptionTest2("Exception in cleanup only", SuccessfulAction, ThrowingCleanup)
ExceptionTest2("Exception in main and cleanup", ThrowingAction, ThrowingCleanup)
End Sub
End Module
The module above starts with a couple helper modules which should probably be in their own "Exception helpers" module. The ExceptionTest method shows the pattern for code which might throw an exception in both the Try and Finally block. The ExceptionTest2 method calls ExceptionTest and reports what exception if any comes back from it. ExceptionDemo calls ExceptionTest2 in such a way as to cause exceptions in different combinations of the Try and Finally blocks.
As shown, if an exception occurs during cleanup, that exception will be returned to the caller, with the original exception being an item in its Data dictionary. An alternative pattern would be to catch the exception that occurs on cleanup and include it in the data of the original exception (which would be left uncaught). My general inclination is that it's probably better in many cases to propagate the exception that occurs during cleanup, since any code which was planning to deal with the original exception will probably expect that cleanup succeeded; if such an expectation cannot be met, the exception that escapes should probably not be the one the caller was expecting. Note also that the latter approach would require a slightly different method of adding information to the original exception, since an exception which is thrown in a nested Try block might need to hold information about multiple exceptions that were thrown in nested Finally blocks.
I get this error at the Commit of a transaction in a desktop application:
This OleDbTransaction has completed; it is no longer usable.
Other posts I have seen with similar error suggests this can occur if it takes a long time, or contains large amounts of data. This is not the case here. Logging tells me it takes 140 ms from Begin to Commit and about 10 commands executed inside the transaction.
It is using an Oracle database.
This class is a simplified version of my database class:
Class MyDatabase
Private mConnection AS OleDbConnection
Private mTransaction AS OleDbTransaction
Function Value(ByVal piSql As String) As Integer
Try
Dim lCommand As OleDbCommand
lCommand = New OleDbCommand(piSql, mConnection)
If mTransaction IsNot Nothing Then
lCommand.Transaction = mTransaction
End If
Dim lValue = lCommand.ExecuteScalar()
If Not lValue Is Nothing Then
WriteLog(lValue.ToString(), 3, "Value Returned")
Return lValue.ToString()
Else
WriteLog("<null>", 3, "Value Returned (null)")
Return ""
End If
Catch ex As Exception
WriteLog(ex.Message)
End Try
End Function
Function ExecuteSql(ByVal piSql As String) As Integer
Try
Dim lCommand As OleDbCommand
lCommand = New OleDbCommand(piSql, mConnection)
If mTransaction IsNot Nothing Then
lCommand.Transaction = mTransaction
End If
Return lCommand.ExecuteNonQuery()
Catch ex As Exception
WriteLog(ex.Message)
End Try
End Function
Public Sub BeginTransaction()
Try
mTransaction = mConnection.BeginTransaction()
Catch ex As Exception
WriteLog(ex.Message)
End Try
End Sub
Public Sub Commit()
If Not mTransaction Is Nothing Then
Try
mTransaction.Commit()
Catch ex As Exception
WriteLog(ex.Message)
End Try
mTransaction.Dispose()
mTransaction = Nothing
End If
End Sub
Public Sub Rollback()
If Not mTransaction Is Nothing Then
Try
mTransaction.Rollback()
Catch ex As Exception
WriteLog(ex.Message)
End Try
mTransaction.Dispose()
mTransaction = Nothing
End If
End Sub
End Class
Calling code (simplified):
mDatabase.BeginTransaction()
mOrderId = mDatabase.Value("select max(order_id) from ler_order")
mDatabase.ExecuteSql("insert into ler_order (order_id,status,message,plotter,reference,paper_size,orientation,plot_scale,format,usr,email,no_of_copies,date_time,uservar1,uservar2,uservar3,ell,nll,eur,nur,coord_type,graveforespoergselanmodningid,graveforespoergselnr,oprettetdato,aendretdato,graveartnavn,andengraveart,lek_virksomhed,lek_navn,lek_adresse,lek_postnr,lek_postdistrikt,lek_land,lek_telefon,lek_mobiltelefon,lek_telefax,lek_email,ga_navn,ga_adresse,ga_postnr,ga_postdistrikt,ga_land,ga_telefon,ga_mobiltelefon,ga_telefax,ga_email,gak_id,gak_virksomhed,gak_navn,gak_adresse,gak_postnr,gak_postdistrikt,gak_land,gak_telefon,gak_mobiltelefon,gak_telefax,gak_email,emailafsendt,konverteringsstatus) values (101633,0,null,'LER','10d6d8bc-b9b2-44bb-84bf-ceca42a0970a',null,0,0,null,null,null,0,'09-05-2011 13:25:33',null,null,'VAND',-259954.967,145092.123,-259802.657,145147.225,1,'10d6d8bc-b9b2-44bb-84bf-ceca42a0970a',425950,'09-05-2011 13:20:27','09-05-2011 13:20:58','Gravemaskine',null,null,'Ledningsoplysning','Kokbjerg',null,'Kolding',null,'59 23 44 55',null,null,'info#mail.com','FORSYNINGSLEDNINGER','vej 12','1700','Nyberg','NO','21491697',null,null,'mail#info.com','051055f4-ea2a-4cb3-a016-6f6477e6a342','MUNCK FORSYNINGSLEDNINGER A/S','Jon Andersen','vej 38 B','7100','Vejle','NO',null,'23681515','76409220','mail#info.com','09-05-2011 13:20:58','OK')")
mDatabase.ExecuteSql("delete from ler_order_coord where order_id = 101633")
mDatabase.ExecuteSql("insert into ler_order_coord (order_id,polygon_no,seq_no,east,north) values (101633,1,1,-259954.967,145120.599)")
mDatabase.ExecuteSql("insert into ler_order_coord (order_id,polygon_no,seq_no,east,north) values (101633,1,2,-259951.933,145092.123)")
mDatabase.ExecuteSql("insert into ler_order_coord (order_id,polygon_no,seq_no,east,north) values (101633,1,3,-259802.657,145111.956)")
mDatabase.Commit() 'This is where the error occurs
EDIT:
See my answer for how I solved this.
I have a follow-up question on this: Is it not allowed to run a select inside a transaction like this? Or can it be done by running the transaction in a specific isolation level (I see that the BeginTransaction method has an optional parameter for doing this) ? ..Or some other sollution..? In my case, it was not a problem to move the select to run before the transaction started, but what if you need to run selects that must run inside the transaction?
I found an answer to another question, which helped me along the way:
How to check if Dotnet transaction is rolled back?
I implemented the TransactionScope to have better control on my transaction, and I noticed a new error message in the log saying :
The Transaction Manager is not available. (Exception from HRESULT: 0x8004D01B)
This error was triggered on the select statement:
mOrderId = mDatabase.Value("select max(order_id) from ler_order")
I moved the select to before the transaction begins, and now it works!
EDIT:
I discovered that what triggered this error might not have been the use of TransactionScope, but that I tried to set lCommand.Transaction = mTransaction on the select command. This is apparently not allowed when the command is not an action command. This is however not the original problem, because the error on Commit was there before I tried to set the active transaction on the select command. This is just something I tried along the way trying to fix it.