Is it possible/a good idea to dispose of a thread in its catch and re instantiate itself in the finally block? - vb.net

Background: I have multithreaded application that has one main UI thread and two threads that are super loops that run for the duration of the program. The worker threads basically read in some information and write an output to a Program Logic Controller.
I am running into an issue that I can't repeat when I'm debugging but only happens when the program is compiled and ran as an executable. I know the proper way of dealing with my issue is to find out why this is happening and deal with it. But while I am doing that I was wondering if it was possible to handle this issue in a different way...
Quesiton :
My entire worker thread is in a
Try
Catch ex As Exception
Finally
End Try
Is it good practice / and even possible for me to dispose of my worker thread in the catch when it hits an exception and then restart / reinstantiate itself in the finally block?
I would Imagine a response to this might be "No thats not good practice because if you hit the exception mid loop, you will lose all the states of all your objects in your thread and if you restart it it might throw things out of sync."
This isn't actually going to be a problem for me, because all the states of all my objects are updated real time on the PLC, and the very first thing I do when I start my worker thread is read from the PLC to get all the states of all my objects.
The root of my question is, can a thread restart itself in the finally block?

If you changed your thread code from this
Do While True
'your code here
Loop
to this
Do While True
Try
'your code here
Catch ex As Exception
End Try
Loop
then the thread can only exit if you have an Exit Do or an exception is thrown by the code in the catch block.

It definitely isn't good practice, but it can be done. However, you would want to restart it in the Catch block, not the Finally block. The Finally block gets called at the end of the Catch, but it also gets called if the Try block finishes execution.

To specifically answer your question; Is it possible? Yes - you can do something like this:
Public Sub Main
'define thread object outside the Try block so we can use it
'again in the Catch block
Dim thr as Thread
Try
thr = New Thread(AddressOf SuperLoop1)
thr.Start
Catch
'you may want to log the exception so you know it has happened
thr = New Thread(AddressOf SuperLoop1)
thr.Start
End Try
End Sub
Sub SuperLoop1
'code for "super loop 1"
End Sub

Related

Catch Exception Message without stopping

I have a simple Try Catch function like:
Try
'do that
Catch
'didn't work now try again
End Try
Now I want the Error / Catch Message to be displayed as Messagebox which works with:
Catch ex As Exception
Messagebox.Show(ex.message)
The issue with that is that it always Stops / Quits the Application after showing me the Error Message which I want to prevent. This should try something until it works and always display the error message without stopping. Is that possible? I need it as compiled exe so just Debugging won't be an option.
As Explanation what I am trying to do:
Basically I have a Timer that executes every 10 Seconds a Request to my Server. It check if my Server is up and connected. If it can't reach my Server it should exactly display me the Message why it didn't connect but it shouldn't stop, it should continue pinging my server 10 seconds later again and try again until it works. The thing is that the exception message sometimes changes so I really need the Exception Message as output
It sounds like right now you have a method that sometimes throws like this:
Public Sub CheckServer()
' do something to test the server
End Function
If the code is not isolated to it's own method like that, it should be.
And you want to call it like this:
Try
CheckServer()
Catch ex As Exception
MessageBox.Show(...)
End Try
I suggest moving the Try/Catch inside the method and making it return a value:
Public Function CheckServer() As String
Try
' do something to test the server
Catch ex As Exception
Return ex.Message
End Try
Return String.Empty
End Function
And then call it like this:
Dim errorMessage As String = CheckServer()
If Not String.IsNullOrEmpty(errorMessage) Then
SendAlert(errorMessage)
End If
Where you also have a separate alert method:
Public Sub SendAlert(alertText As String)
SomeControl.Text += $"{Now} -- {alertText}{vbCrLf}"
End Sub
Notice I did not use MessageBox, because it blocks your UI. But the idea here is this makes it easy to change what you want to do with the alerts when they come in. For example, you might create a toast notification.
Since you're using WinForms, the other thing you could do here is define and then raise an event, rather than returning a value.
Are you using TCPClient to connect ??? If you are, you can just write an IsConnected code. TCP client stays connected until the server or client go out.
The most common error message when a server is not accepting connections is the “server did not properly respond in time message”
Constantly sending the server a request isn’t ideal. You need a one notification to come through when the connection is lost... and then set the timer to constantly try to reconnect.

Is there a way to handle SQLExceptions that are generated by SqlDataSource

I have been experiencing a problem with one of my vb applications where it is crashing at a certain time of day. In my code, there are only 4 places where that could be the cause of the crash. Three of them are from SQLDataSource queries and the other is in the code behind. I am pretty sure that I don't have a problem with the code behind as I have a using block in place. Further more, inside of that block I have a try catch finally where in the finally I am Disposing the command as well as the connection and Closing the connection. I have been reading some articles that tell me that I should use a SqlDataSource "selected" event to close the connection. I gave that a try but didn't have any success. This is the error that I am receiving:
SqlException (0x80131904): Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
This makes me feel like the "selected" event is not having a chance to get fired. So I thought I should try the "selecting" event. In it, I am trying to grab the connection string and close it. But I am not quite sure I am going down the correct path because I have been unable to catch exceptions inside of that event. Can someone out there please give me a hand with this issue I am facing?
Edit:
This is an example of how I am trying to use the selected event to close the connection
If Not IsNothing(e.Exception) Then
Debug.Print("Exeception encounted while selecting for sqlData")
End If
e.ExceptionHandled = True
And here is and example of how I am trying to use the selecting event (I cannot figure out if an exception has been thrown here).
Dim sqlDataConn As SqlConnection = New SqlConnection("MYConnectionString")
sqlDataConn.Dispose()
If you want to intercept SqlException you need to use explicit "using", i.e. try/catch. Then, you can determine specific issue by the Number property.
try
catch ex as SqlException
MessageBox.Show(ex.Number)
if ex.Number = xxx then
' do something
end if
catch ex as Exception
finally
end try
if the question about handling this
If Not IsNothing(e.Exception) Then
Debug.Print("Exeception encounted while selecting for sqlData")
End If
you can check the exception type
If e.Exception IsNot Nothing AndAlso TypeOf e.Exception Is SqlException Then
.....
It would help if you did a breakpoint and found the query that was having this issue. The timeout issue is when a long-running query kills itself because it ran past the default timeout period.
A quick and dirty solution could be to just use a larger timeout in the connection strings you use, but long running queries can usually be a bad sign of an unoptimized query and should be addressed before your database grows any larger.

Understanding the Open method and the Try block in VB.NET

I'm using VB.NET for the first time, to check if a file is in use, but there are some lines of code that I don't fully understand.
Can someone explain the two lines of code highlighted below in the comments?
Public Sub Main()
IsFileInUse("C:\someFolder\file.pdf")
End Sub
Function IsFileInUse(filePath As String) As Boolean
IsFileInUse = False
If System.IO.File.Exists(filePath) Then
Dim fileInfo As System.IO.FileInfo
Dim stream As System.IO.FileStream
fileInfo = New System.IO.FileInfo(filePath)
Try
' Can someone explain this line of code?
' how does this determines where to go from here, Catch or Finally?
stream = fileInfo.Open(System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None)
Catch
IsFileInUse = True
MessageBox.Show("It looks like the file is opened")
Finally
If stream IsNot Nothing Then
' What is this closing?
stream.Close()
End If
End Try
Else
MessageBox.Show("File does NOT Exist")
End If
End Function
how does this determines where to go from here, Catch or Finally?
Look at the documentation for FileInfo.Open. The Exceptions section shows all of the possible exceptions that can happen.
If an exception is thrown, the Catch block will be executed.
The Finally block always gets executed, whether or not an exception was thrown.
What is this closing?
It will release the stream's resources, in this case it will close the file.
The Try block runs the code. In the Try block, a stream is used to open the file and access its contents. If that code errors for any reason, it will throw an Exception, which will then cause to the Catch block to be run. The Finally block of the code will run whether an Exception is thrown or not. In the Finally block, the stream to the File is being closed.
The code is determining whether or not the file is currently "in use" by any other processes by attempting to open the file with read/write access. Whether the opening of the file fails or not, it always closes the file stream. It assumes that if opening the file in that mode fails for any reason, then it must be because it is "in use". That's a bad assumption to make, and likely not the best way to accomplish it anyway, but for what it's worth, that's what it's doing.
The Try/Catch block is VB.NET's preferred syntax for exception handling (it replaces the older On Error syntax which predated .NET). When anything inside of the Try section throws an exception, execution will jump to the Catch section. Once execution of the Catch section completes, it then jumps to the Finally section. If nothing in the Try section throws an exception, then once it's done, it also jumps to the Finally section. Essentially, everything in the Finally section is "guaranteed" to execute, whether or not an exception occurred, whereas the code in the Catch section only executes when there is an exception.
In other words, consider this example:
' Outputs "ABCE" (does not output "D")
Console.Write("A")
Try
Console.Write("B")
Console.Write("C")
Catch
Console.Write("D")
Finally
Console.Write("E")
And compare it to this example:
' Outputs "ABDE" (does not output "C")
Console.Write("A")
Try
Console.Write("B")
Throw New Exception()
Console.Write("C")
Catch
Console.Write("D")
Finally
Console.Write("E")
See the MSDN article for much more information on the topic.

thread pool error trapping

Checking on a best practice here.
I am calling a ThreadPool to run an Async process, specifically sending an SSL email with an attachment which seems to take a good long while.
This is just test code, I thought I would drop this in a Try Catch just incase something failed. But will the thread ever even come back here? I have tested this closing the web page, the browser, clicking the back button on the page. The email always makes it through.
Try
System.Threading.ThreadPool.QueueUserWorkItem(AddressOf DoAsyncWork) '
Catch ex As Exception
Throw ex
Exit Sub
End Try
I am not trying to force a failure, yet I guess, but I would like to know how best to trap if the thread fails.
Protected Sub DoAsyncWork(ByVal state As Object)
Dim oMyObject As New sendSSLemail
oMyObject.SSL(userName, , strMessageBody, emailAdd, , permFileLocation, , "CodeMsg")
End Sub
A more convenient way of doing work with the thread pool is to use Task.Factory.StartNew(Action). It returns a Task object which can be Awaited or blocked on with Wait.
Once the task completes, the Exception property of the Task can be used to determine whether an exception was thrown and unhandled by the task's subroutine. (If it's not Nothing, then the InnerException property has the real exception that was thrown.)
Dim task = Task.Factory.StartNew(AddressOf WorkFunction)
' do stuff that doesn't depend on WorkFunction having completed
task.Wait()
If task.Exception IsNot Nothing Then Throw task.Exception.InnerException
After a Throw, the sub is exited anyway (the call stack is unwound looking for a Catch), so the Exit Sub statement does nothing. Wrapping a QueueUserWorkItem call in a try block also does nothing, because any exception would occur on the other thread. You would only get exceptions thrown immediately by QueueUserWorkItem, which off the top of my head only includes complaints about the delegate being Nothing.
Asynchronous tasks can also return values. For more information on that, see the TaskFactory methods that return a Func(Of Task).

StackOverFlow Exception using Background Thread in vb.NET

i'm using a background Thread in vb.net to connect/reconnect to a device.
It's working fine, but after around 2 hours, the programm is throwing a stackoverflow exception, in the following part of my code:
if connected = True then
Thread.Sleep(500)
Exit sub
endif
After that, i'm calling the Sub again.
I know, i could just set the Sleep-Time to e.g. 1000 ms, but i think this isnt the nicest solution...
Would a "Backgroundworker" (using visual studio) be the better solution/ solve my Problem?
Or is there a posibility to clean the stack?
Thanks for your help!
EDIT:
Module connection
Public Sub connect()
connect_loop()
connect()
End Sub
Public sub connect_loop()
if connected = True Then
**HERE IS WHERE THE EXCEPTION IS THROWN**
Thread.Sleep(500)
Exit Sub
Endif
'Code for the Connection (ping, open Socket etc.)....
End Sub
End module
The module is started from my main routine as a background thread:
Public background As New Thread(AddressOf connection.connect)
background.IsBackground = True
background.Start()
Do you need the Code for the connection? I didn't wrote it here, because the Exception is not thrown in the real connection part. Also, 2 hours everything works fine.
Your method connect is recursive without any condition under which it will return.
Each call to a function or method will make use of some stack space, and each thread only has so much stack space.
If you want connect to loop for ever just use an infinite loop (but consider how the lop will exit when you want to stop the process).
Public Sub connect()
...
connect()
End Sub
So which part of the obvious stack overflow is unclear to you? You are calling connect recursively w/o any criteria. It will stack overflow, guaranteed. Your Sleep() only delays the inevitable. Threading has nothing to do with the problem. You may want to do somehting like a loop instead:
while(true)
connect_loop()
end
(or whatever is the VB syntax for a while loop).