TPL Exception - How to attach to the main thread - .net-4.0

I am planning to implement TPL in my existing asp.net application to improve the performance.
I am implementing them in the selective places (like calls to write data to one table and some kind of irrelevant and non sync operations ), and we are processing all the unhandled exception in the application_error event in the global.asax file.
But when I get an error the TPL its not throwing that error to the application_error event.
When I tried with Task.WaitAll(t1) then its throwing to app_error event, but its taking a while to process the written code.
But when I try with the following method (to take some time only when fault is occurred) then also its not throwing the exception to the main thread.
Task.Factory.StartNew(Sub(mainContext)
HttpContext.Current = mainContext
LookUpRepository.AddItems(CurrentContext.LoggedInUser.UserID, ClientID)
End Sub, HttpContext.Current).ContinueWith(Sub(tplException)
For Each ex In tplException.Exception.InnerExceptions
Throw ex
Next
End Sub, TaskContinuationOptions.OnlyOnFaulted Or TaskContinuationOptions.ExecuteSynchronously)
I tried with ConcurrentQueue to catch the exceotion and sometimes it halts the applcation and the control is not proceeding further line of code.
So how can I attach the the TPL exceotion to the main thread which is hosting the asp.net application.

There is an observable collection ObservableCollection that is available in .Net. If there is an error in the thread that we opened and if we add them in this ObservableCollection , then it will raise an event, From that event we can handle this error
Task.Factory.StartNew(Sub(mainContext)
'Using sw As StreamWriter = File.AppendText("c:/logs/t7.txt")
' sw.WriteLine("thread=" + Thread.CurrentThread.ManagedThreadId.ToString())
'End Using
HttpContext.Current = mainContext
'Do some operation
End Sub, HttpContext.Current).ContinueWith(Sub(tplException, subContext)
HttpContext.Current = subContext
If IsNothing(tplException.Exception) Then Exit Sub
For Each ex In tplException.Exception.InnerExceptions
MyAppState.Instance.ObservableException.Add(ex)
Next
End Sub, HttpContext.Current)
Collection needs to declared
Public WithEvents ObservableException As ObservableCollection(Of Exception)
Event that will get raised by .Net framework to handle the exception
Private Sub CollectionChangedHandler(sender As Object, e As NotifyCollectionChangedEventArgs) Handles ObservableException.CollectionChanged
Dim ex = DirectCast(e.NewItems(0), Exception)
ExceptionLog.SaveFile(ExceptionLog.ReadExceptionInformationFromException(ex))
End Sub

Related

Exception handling with Async Task functions

I am beginning to learn about Async / Task functions for running cancellable SQL queries in VB.NET.
I have the following code in a class library which runs two tasks and does not have any exception handling, as I would like to handle this in the application that calls the class library. I have the following code in the class library.
Public Async Function DirectoryList(ct As CancellationToken) As Task(Of List(Of Directory))
ct.ThrowIfCancellationRequested()
Dim ds As DataSet
Dim dirs As List(Of Directory)
Dim ctUnregister As CancellationTokenRegistration
ds = Await Task.Run(Function()
Using newConnection = New SqlConnection(Me.InitializationData.ConnectionString)
Using sqlAdapter = New SqlDataAdapter("DirectoryList", newConnection)
ctUnregister = ct.Register(Sub() sqlAdapter.SelectCommand.Cancel())
With sqlAdapter
.SelectCommand.CommandType = CommandType.StoredProcedure
.SelectCommand.CommandTimeout = Me.InitializationData.CommandTimeout
End With
Dim newDataSet As DataSet = New DataSet()
sqlAdapter.Fill(newDataSet)
Return newDataSet
End Using
End Using
' Remove the registration we set earlier so the cancellation token can be used normally.
ctUnregister.Dispose()
End Function, ct)
dirs = Await Task.Run(Function()
Dim dirsResult As New List(Of Directory)
Dim tbl As DataTable = ds.Tables(0)
For Each row As DataRow In tbl.Select()
' process the data
ct.ThrowIfCancellationRequested()
Next
Return dirsResult
End Function, ct)
Return dirs
End Function
I then call it as follows:
Try
dirs = Await databaseLibrary.DirectoryList(cts.Token)
MsgBox("Query complete!")
Catch ex As System.Data.SqlClient.SqlException
MsgBox("Cancelled (SQL)")
Catch ex2 As OperationCanceledException
MsgBox("Cancelled")
Catch ex3 As Exception
MsgBox("Cancelled")
End Try
Functionally it seems to work as expected - I can cancel the requests and exceptions are thrown as expected.
However I would like to handle the exceptions so I can gracefully cancel the tasks, but even when running in Debug mode within the IDE, the app still breaks and the exception (e.g. SqlException) is shown within the IDE. If I step on, eventually the Catch logic runs.
When the application is run outside of the IDE, the exception handling works as expected.
This seems different to the normal behaviour when running in the debugger- normally the exception handling runs but only breaks if the exception is unhandled.
Why is this behaviour different, presumably because of the Async functions?
when running in Debug mode within the IDE, the app still breaks and the exception (e.g. SqlException) is shown within the IDE.
Why is this behaviour different, presumably because of the Async functions?
Exceptions thrown by asynchronous functions are not caught directly by the catch. What actually happens is that the exception is caught by a compiler-generated state machine, and that exception is placed on the returned Task. Later, when that task is awaited, the exception is re-raised, and then can be caught by the catch.
However, this "indirection" in exception handling means that the IDE does kind of freak out when the exception is initially thrown. As far as it can tell, there is no catch in your code that is going to catch it, so that's why it breaks and displays the exception. It doesn't know that the compiler-generated code will catch it. You can tell the IDE not to worry about uncaught exceptions.

Handling Cross Thread Exception in Vb.Net Forms

I have a windows form on to which i have declared custom controls ( label, panels text boxes), The issue is I am loading images of that control in local thread , but some of the pictures not not downloading from web stream, hence the exception, Now i am setting image property Nothing in Catch block, and trying to set other UI panels properties, but it throws exception,
Exception :
"Cross thread operation not valid: Control "XXXXXXXXXX" accessed from a thread other than the thread it was created. "
kindly somebody tell the simplest way to set the property in case of exception occur so I may set the properties of other controls.
Basically, you don't touch controls in methods executed on a secondary thread. Only touch controls on the UI thread. Where you might usually just do this:
myPictureBox.Image = myImage
you now write a method like this:
Private Sub SetPictureBoxImage(img As Image)
If myPictureBox.InvokeRequired Then
myPictureBox.BeginInvoke(New Action(Of Image)(AddressOf SetPictureBoxImage), img)
Else
myPictureBox.Image = img
End If
End Sub
and then call it on the secondary thread instead of setting the Image property directly:
SetPictureBoxImage(myImage)
Note that that method will succeed whether it's called on the UI thread or a secondary thread so you can call it whether you know that you're on a secondary thread or not.
Check this out for more information.
EDIT
Private Sub UpdateUI(img As Image, visible As Boolean)
If Me.InvokeRequired Then
Me.BeginInvoke(New Action(Of Image, Boolean)(AddressOf UpdateUI), img, visible)
Else
myPictureBox.Image = img
myPanel.Visible = visible
End If
End Sub
Note that I used the InvokeRequired and Invoke members of the form instead of a specific control. It actually doesn't matter which form or control those are members of as long as they are owned by the same UI thread but to me it seems logical to use the same control your updating if there's only one or else use the form.
Note also that the signature of the delegate changes to match the signature of the method so that they have the same number and type of parameters.
I have done that UI change in this function:MethodInvoker
Try
'Code that was throwing exception here
Catch ex As Exception
Me.Invoke(New MethodInvoker(Sub()
'All UI changes made here
End Sub))
End Try
Control.CheckForIllegalCrossThreadCalls = False
Will allow you to change your TextBox,Label and etc... in execution

How do I solve 'System.OutOfMemoryException'

I have a Windows Service application. It is a very busy application. It is supposed to run continuously looking for things to do. After it runs for a while I get
Exception of type 'System.OutOfMemoryException' was thrown.
It can happen at different times but usually a this paragraph:
Private Shared Function GetUnprocessedQueue() As Boolean
Try
Dim l_svcOOA As New svcITGOOA.IsvcITGOOAClient(OOAProcessing.cGlobals.EndPoint_ITGOOA)
Dim l_iFilter As New svcITGOOA.clsFilter
With l_svcOOA
With l_iFilter
.FilingType = OOAProcessing.cGlobals.FilingType
End With
m_ReturnClass = .itgWcfOOA(1, cGlobals.DatabaseIndicator, svcITGOOA.eOOAAction.GetUnprocessedQueue, l_iFilter, 71)
Return CompletedGetUnprocessedQueue(m_ReturnClass)
End With
Catch ex As Exception
ExceptionHandling(ex, "GetUnprocessedQueue " & m_Application)
Return False
End Try
End Function
This is using a wcf service to read a queue. It reads the queue every two minutes to see if new records have been added to it.
Please help me solve this. I don’t know where to start.
The OutOfMemoryException exception occurs when the GC has completed a cycle of collection but the memory is not available even after that. I couldn't make out what the above code snippet does, but I think using Weak References for objects could be useful.
I had a timer that was generated within the same paragraph that I was setting
For example
m_svcTimer = New Timers.Timer With {.Interval = m_Interval, .Enabled = True}
AddHandler m_svcTimer.Elapsed, AddressOf StartTheQueueIfTime
m_svcTimer.Enabled = True
m_svcTimer.Start()
was within the paragraph StartTheQueueIfTime. I thought this would be a way to change the time interval. Instead it kept creating new events. Finally too many caused my crash.
Bob

Newbie: Invalid cross thread access with using busyindicator (silverlight and wcf service)

I have a problem with the busyindicator control of silverlight.
I have a datagrid (datagrid1) with its source set to a wcf service (client).
I would like to use the busyindicator control (bi) of silvelright toolkit when the datagrid loads itself.
But I have an "Invalid cross thread access" when I use "ThreadPool".
Sub LoadGrid()
Dim caisse As Integer = ddl_caisse.SelectedValue
Dim env As Integer = ddl_env.SelectedValue
bi.IsBusy = True
ThreadPool.QueueUserWorkItem(Sub(state)
AddHandler client.Get_PosteSPTCompleted, AddressOf client_Get_PosteSPTCompleted
client.Get_PosteSPTAsync(caisse, env)
Dispatcher.BeginInvoke(Sub()
bi.IsBusy = False
End Sub)
End Sub)
End Sub
Private Sub client_Get_PosteSPTCompleted(sender As Object, e As ServiceReference1.Get_PosteSPTCompletedEventArgs)
DataGrid1.ItemsSource = e.Result ' Here, Invalid cross thread access
End Sub
I know that the datagrid control doesn't exist in the "new thread", but how have to I make to avoid this error?
Thank you.
William
First point: Why are you using the ThreadPool?
Using a ThreadPool would be a good idea if your service was synchronous, but your WCF service is asynchronous: it won't block your UI thread after being called using Get_PosteSPTAsync.
Second point: there seems to be an issue with your IsBusy property. You're first setting it to true, then you starts an operation asynchronously, then you set it to false immediately. You should set it to false in the Completed handler.
Third point: the client_Get_PosteSPTCompleted handler won't be executed in the same thread as the UI thread (even if you don't use the ThreadPool). That's why you'll have to use the dispatcher here so force using the UI thread.
Your DataGrid1.ItemsSource = e.Result must be modified to:
Dispatcher.BeginInvoke(Sub()
DataGrid1.ItemsSource = e.Result ' Fixes the UI thread issue
bi.IsBusy = False ' Sets busy as false AFTER completion (see point 2)
End Sub)
(note sure about the VB.Net syntax, but that's the idea)
Last point: I don't know about the client object lifetime, but you're adding a new handler to the Get_PosteSPTCompleted each time you call LoadGrid. Maybe you could think of detaching handlers after use.

Handling an exception thrown from inside a dll

I'm working on a project for school in which a dll is loaded.
The dll that is loaded is a bridge between my program and the Twincat System Manager which forms the bridge between the computer and a PLC via the local network.
I need to read Variables trough this whole chain from the plc to my program.
This is the way I do this:
Public Function adsReadReal(ByVal Variabelenaam As String) As Single
Dim ds = New TwinCAT.Ads.AdsStream(4 * 8) ' new data stream
Dim br = New System.IO.BinaryReader(ds) 'new binary
Dim hVar = New Integer
Try
ConState(1)
tcclient = New TcAdsClient
ConState(2)
tcclient.Connect(Form1.amsAdress, 801) 'connects the tcclient to the PLC
hVar = tcclient.CreateVariableHandle(Variabelenaam) 'creats a handle for the variable
tcclient.Read(hVar, ds) 'read it
ConState(5)
Return br.ReadSingle() 'convert it from binary to readable for vb
Catch ex As Exception
ConState(0)
PrintEx(ex) 'print out the exception
finally
tcclient.Dispose() 'make the object stop being used to prevent a lingering connection
End Try
Return False
End Function
Now the program loads a dll called TwinCAT.ADS.dll at the start of the connection module. If the Twincat system manager is running the program ends normally, but when it is not it crashes and gives me this error:
System.DllNotFoundException was unhandled
Message="Kan DLL tcadsdll.dll niet laden: Kan opgegeven module niet vinden. (Uitzondering van HRESULT: 0x8007007E)"
Source="TwinCAT.Ads"
TypeName=""
StackTrace:
bij TwinCAT.Ads.Internal.TcAdsDllWrapper.TcAdsDll.AdsAmsUnRegisterRouterNotification()
bij TwinCAT.Ads.Internal.TcAdsDllWrapper.AmsUnRegisterRouterNotification(Boolean
throwAdsException)
bij TwinCAT.Ads.Internal.TcLocalSystem.Dispose(Boolean disposing)
bij TwinCAT.Ads.Internal.TcLocalSystem.Finalize()
which is roughly translated to:
Cannot load DLL tcadsdll.dll: Cannot find given module. (Exception at
HRESULT: 0x8007007E)
This is not a dll that I have imported, so it must be from the TwinCAT.ADS.dll
How can I prevent the program from throwing this error at me and instead close the program peacefully? I have tried to catch all the exceptions of every dll related operation possible.
Also the source is on Bitbucket. I will make it public on request.
Some links on the official but quite unhandy Beckhoff site:
http://infosys.beckhoff.com/espanol.php?content=../content/1034/tcquickstart/html/tcquickstart_samplevisualbasicnet.htm&id=10449
Edit:
Apparently using tcclient.dispose() causes the error since the finnaly statement was use instead of just after the try block
Edit: This currently catches the exception but it does not handle it.
Dim currentDomain As AppDomain = AppDomain.CurrentDomain
AddHandler currentDomain.UnhandledException, AddressOf MyHandler
Dim tick As Byte = 0
Sub MyHandler(sender As Object, args As UnhandledExceptionEventArgs)
Dim ex As Exception = DirectCast(args.ExceptionObject, Exception)
MsgBox("exception tick" & Str(tick))
tick = tick + 1
PrintEx(ex)
End Sub
Edit:
The exception isn't caught properly because in vs2008 a couple of errors occurs but the tick appears after I press F5 (continue)
When the program is run directly, I only see 1 Tick. Then windows gives an error.
Did you try an unhandled exception handler?
Dim currentDomain As AppDomain = AppDomain.CurrentDomain
AddHandler currentDomain.UnhandledException, AddressOf MyHandler
Sub MyHandler(sender As Object, args As UnhandledExceptionEventArgs)
Dim e As Exception = DirectCast(args.ExceptionObject, Exception)
Console.WriteLine("MyHandler caught : " + e.Message)
End Sub