In Silverlight app I need to run multiple async calls in parallel – they will call server to check data, etc. My pseudo-code-setup looks like this
public interface IAsyncVerifier
{
event EventHandler OnCompleted;
void Verify();
}
// Subscribe to verifier completion events
foreach (var verifier in this.VerifierEngine.GetVerifiers())
{
var asyncVerifier = verifier as IAsyncVerifier;
if (asyncVerifier == null || !asyncVerifier.IsVerifierRunning()) continue;
asyncVerifier.OnCompleted += (s, a) => DoWhat(); // ????????
asyncVerifier.Verify();
}
So, in my mind I have interface common for all those tasks. Then before execution I subscribe to all of their events and … ?
I need to somehow wait for them to complete and proceed with what I’m doing. How to write remaining code properly? I see some kind of counter that I increment every time I call Verify() and decrement every time I get OnCompleted. But I don’t get whole picture on how to wrap it together so it doesn’t smell. Also, Silverlight runs those on background threads if I understand correctly (calls to WCF services)
EDIT:
I’m working with 3rd party verification engine. this.Verifier.VerifierEngine is not something I wrote. I can only add verifiers to collection. Usually they execute on main thread to validate properties, etc. My need is to create verifier that makes call back to server, hence async in Silverlight. I’m not dealing with threads manually, when I make call to service it returns on main thread so it’s fine, this part hidden from me. All I want is to be able to “wait” until all of the verifiers completed. The only way I can check right now is the way I’m doing.
Therefore my UI is quirky. User hits’ save after done modifying field and my verification starts. I check if all verifiers IsVerifierRunning and give user message that he needs to retry. I really need to be able to wait up for all to complete and then proceed.
- I don’t need to worry about threads unless proper solution will involve working with threads
- I have access to results already
I too suggest using the Reactive Framework (Rx) to do what you want.
First up you need a function that will turn
IAsyncVerifierinto an observable that will kick off the verification process and subscribe to theOnCompleted. Here it is:This function uses an
AsyncSubjectto make sure that it captures the event firing.Now the query becomes quite straight forward.
In the Rx world, since this is a
SelectManyquery the default is to run these on the thread pool – so it is run in parallel.The final
.ToArray()call is a little different to the enumerable version of the function. The observable version changes anIObservable<T>(an observable that returns zero or more values) intoIObservable<T[]>(an observable that returns a single array of zero or more values). In other words, this will wait until all of the verifiers are finished before returning them all.Now you just have to subscribe to the query and run whatever code you want to knowing that all the verifiers have completed.
If you want to run some code each time a verifier finishes and when all of them finish then you can take off the
.ToArray()call and subscribe to the query like so:I hope this is all clear enough.