ThreadPool.QueueUserWorkItem and ApplicationContext/ClientContext

ThreadPool.QueueUserWorkItem and ApplicationContext/ClientContext

Old forum URL: forums.lhotka.net/forums/t/10710.aspx


NemisisJedi posted on Friday, September 23, 2011

It was suggested in a previous post that i should use the Csla.Threading.BackgroundWorker to perform some background tasks, but this doesnt seem to be an option anymore, as i need to about 60+ tasks all at once. I tried to split the tasks up and running 1 at a time, but the Completed event in the Csla.Threading.BackgroundWorker never seems to fire??  bug??  Not sure, will post code below.

I was wondering, that since i have so many tasks, could i use ThreadPool.QueueUserWorkItem??  This seems to offer a good way to queue the tasks up, but when the task is passed to the queue, the ApplicationContext/ClientContext are blank and i need these populating to run my code.

How can i use ThreadPool.QueueUserWorkItem and also ApplicationContext etc??  Anyone know how to copy the values over, or is there a csla.ThreadPool.QueueUserWorkItem??

My code that wasnt firing the Completed event for the BackgroundWorker is as follows.  I call the code using

Dim lAsyncProcess as New AsyncProcess(Objects Here)

lAsyncProcess.Run()

----------

Public Class AsyncProcess

 

            Public Class AsyncWorker

 

                Public Report As IBaseReport

                Public WaitHandle As AutoResetEvent

 

                Public Sub New(ByVal pReport As IBaseReport, ByVal pWaitHandle As AutoResetEvent)

                    Report = pReport

                    WaitHandle = pWaitHandle

                End Sub

 

            End Class

 

            Public WaitHandle1 As WaitHandle

            Public WaitHandle2 As WaitHandle

            Public BuiltReports As Dictionary(Of Integer, IBaseReport)

            Public WithEvents BackgroundWorker1 As New Csla.Threading.BackgroundWorker

            Public WithEvents BackgroundWorker2 As New Csla.Threading.BackgroundWorker

 

 

            Public Sub New(ByVal pReports As Dictionary(Of Integer, IBaseReport))

                BuiltReports = New Dictionary(Of Integer, IBaseReport)

 

                Dim lLoopCount As Integer

 

                ' create wrappers

                While lLoopCount < pReports.Count

                    BuiltReports.Add(pReports.ElementAt(lLoopCount).Value.ReportId, pReports.ElementAt(lLoopCount).Value)

                    lLoopCount += 1

                End While

            End Sub

 

            Public Sub Run()

 

                Dim lLoopCount As Integer = 0

                Dim lWaitHandles As New List(Of AutoResetEvent)

 

                While lLoopCount < BuiltReports.Count

 

                    lWaitHandles.Clear()

 

                    lWaitHandles.Add(New AutoResetEvent(False))

                    BackgroundWorker1.RunWorkerAsync(New AsyncWorker(BuiltReports.ElementAt(lLoopCount).Value, lWaitHandles(0)))

                    lLoopCount += 1

 

                    If lLoopCount < BuiltReports.Count Then

                        lWaitHandles.Add(New AutoResetEvent(False))

                        BackgroundWorker2.RunWorkerAsync(New AsyncWorker(BuiltReports.ElementAt(lLoopCount).Value, lWaitHandles(1)))

                    End If

 

                    WaitHandle.WaitAll(lWaitHandles.ToArray)

 

                    lLoopCount += 1

 

                End While

 

            End Sub

 

            Public Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork, BackgroundWorker2.DoWork

                Dim lAsyncWorker As AsyncWorker = DirectCast(e.Argument, AsyncWorker)

 

                lAsyncWorker.Report.Build()

 

                'lAsyncWorker.WaitHandle.Set()

 

                e.Result = Nothing

            End Sub

 

            Public Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted, BackgroundWorker2.RunWorkerCompleted

                Dim lAsyncWorker As AsyncWorker = e.Result

                Dim lIndex As Integer = 0

 

                While lIndex < BuiltReports.Count

                    If BuiltReports.ElementAt(lIndex).Value.ReportId = lAsyncWorker.Report.ReportId Then

                        BuiltReports(lAsyncWorker.Report.ReportId) = lAsyncWorker.Report

 

                        lAsyncWorker.WaitHandle.Set()

                        lIndex = BuiltReports.Count

                    End If

                    lIndex += 1

                End While

            End Sub

 

        End Class

 

JonnyBee replied on Sunday, September 25, 2011

Hi,

In a "rich" client the ApplicationContext is actually storerd in a named slot on the Thread.

The methods required to set the application context is internal in Csla.

You may look into Csla.Threading.Backgroundworker to see how the "object" + ApplicationContext, CultureInfos and User is wrapped in an object and sent to the background thread. The background thread must then make sure to set these on the background thread before calling the actual method. You could use MethodCaller or reflection to call that method on the ApplicationContext (even if it is internal).

Copyright (c) Marimer LLC