I have already written the WCF endpoint called ExecuteCannedReport which takes a report id and returns a byte array containing the pdf representation of the report. Everything works except the call blocks the main program while the report is being created. The endpoint itself does not need to know if it is being called synchronously or asynchronously so nothing has to change there.
I started by modifying the service reference in the client so that the "Generate asynchronous operations" checkbox is checked ...
This makes Begin<service> and End<service> methods available. I can now invoke the service asynchronously like this...
Private PurSvc As New PurchasingServiceReference.PurchasingClient
-----------------------------------------------------------------
PurSvc.BeginExecuteCannedReport(ReportID, AddressOf CannedReportFinished, Nothing)
Notice that the service reference (PurSvc) must be global because it must be reachable by the CannedReportFinished method that is called when the service completes.
The Begin<service> method adds two new parameters to the synchronous <service> method. The first new parameter is the address of the method that will be called when the service completes or errors. The second new parameter is an optional AsyncState which I'm not using. This line of code launches a new WCF request and immediately continues - thus it is non-blocking.
When the service completes or errors the CannedReportFinished method will be called with an IAsyncResult parameter. It might look something like this...
Public Sub CannedReportFinished(Result As IAsyncResult)
Dim CannedReport As PurchasingServiceReference.CannedReport = Nothing
Try
CannedReport = PurSvc.EndExecuteCannedReport(Result)
Catch ex As Exception
MessageBox.Show("Failed to create report: " & ex.Message)
End Try
End Sub
Calling End<service> with the correct IAsyncResult will block until that particular Begin<service> completes. The AsyncResult parameter allows you to specify which particular call you are waiting for. This allows you to architect your asynchronous calls is different ways. For example, you don't have to use a callback if you don't want to
If the endpoint raised an exception, the same exception will get raised again by the End<service> call, which can be trapped and processed as desired.
You might be tempted to update the UI in the callback. If you do so you will raise an exception that states that the UI object is owned by a different thread. Try this instead...
Dispatcher.Invoke(Sub() UpdateWithResults())
Public Sub UpdateWithResults()
RTFButton.Visibility = Windows.Visibility.Visible
PDFButton.Visibility = Windows.Visibility.Visible
CSVButton.Visibility = Windows.Visibility.Visible
End Sub
No comments:
Post a Comment