smatter
smatter

Reputation: 29228

Silverlight: Moving service calls and file processing to background thread

Is the ProcessFile() running on UIThread or a separate thread. If it is on the UIThread, how to move file request and ProcessFile() to a separate Thread?

var xClient = new ServiceReference1.Service1SoapClient();
 xClient.Retrieve_File_Completed += new EventHandler<ServiceReference1.Retrieve_File_CompletedCompletedEventArgs>(xClient_Retrieve_File_Completed);
.
.//called on Page load
foreach(fileName in fileNames)
{
     xClient.Retrieve_FileAsync(fileName); 
}
.
.
void xClient_Retrieve_File_Completed(object sender, ServiceReference1.Retrieve_File_CompletedCompletedEventArgs e)
{
   //Processing 
   ProcessFile(e.Result[0]); //Is this on UI Thread?
}

EDIT: From the answers, it is clear that ProcessFile() runs on UI thread. How could the file requests and the processing (ProcessFile()) be moved to a separate Thread. ProcessFile just populates some data structures using which UI is changed after all the files are received.

Upvotes: 4

Views: 405

Answers (2)

Jakob Christensen
Jakob Christensen

Reputation: 14956

The service proxies that are generated automatically by Visual Studio when using the "Add Service Reference" feature will automatically dispatch the completed callback events on the thread that initiated the service call.

In your case it means that xClient_Retrieve_File_Completed is indeed executed on your UI thread.

Update: It is actually kind of hard to put the file requests and the file processing all on one thread and then update the UI after all requests and processing has finished because you have to keep the thread alive while the requests to the service are all done. There is no guarantee that the service requests will complete in the same order that they are sent so you have to keep track of the number of completed requests and only when all requests have completed you can notify the UI and end the thread.

To me this sounds as a brittle and complex design and unfortunately the CountDownEvent that you might use for such a design does not exist in Silverlight.

Alternatively you might consider changing the design of your service and of ProcessFile so that you can request and process all files at the same time so you only have to make one service request (unless you are sending loads of data across the network to and from the service). You could then spawn a BackgroundWorker (as suggested by Matthew Paul Keelan in his answer) to process all the files in one shot. Your code would then look similar to this:

// Called on Page load.
// Note that there is only one service call with all file names as parameter.
xClient.Retrieve_FileAsync(fileNames); 

// ...
// Elsewhere in the class
BackgroundWorker _worker;

void xClient_Retrieve_File_Completed(object sender, ServiceReference1.Retrieve_File_CompletedCompletedEventArgs e)
{
    _worker = new BackgroundWorker()
    _worker.DoWork += (sender, args) =>
    {
        // Only one call to ProcessFile.
        ProcessFile(e.Result);
    };

    _worker.RunWorkerCompleted += (sender, args) =>
    {
        // Update UI here
    };
    _worker.RunWorkerAsync();
}

Upvotes: 2

Matthew Keelan
Matthew Keelan

Reputation: 536

You can determine if the code is executing on the UI thread using the Dispatcher.CheckAccess() method:

Dispatcher.CheckAccess Method

If the ProcessFile method is an expensive operation, you could try offloading it to a BackgroundWorker. Pete Brown has a nice description of how to do this here:

The UI Thread, Dispatchers, Background Workers and Async Network Programming

Upvotes: 1

Related Questions