views:

1598

answers:

3

Hi,

Part of my Silverlight application requires data from three service requests. Up until now I've been chaining the requests so as one completes the other starts... until the end of the chain where I do what I need to do with the data.

Now, I know thats not the best method(!). I've been looking at AutoResetEvent (link to MSDN example) to thread and then synchronize the results but cannot seem to get this to work with async service calls.

Does anyone have any reason to doubt this method or should this work? Code samples greatfully received !

Paul.

+3  A: 

Take a look at this example:

Will fire Completed event and print 'done' to Debug Output once both services returned. Key thing is that waiting for AutoResetEvents happens in background thread.


public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        Completed += (s, a) => { Debug.WriteLine("done"); };

        wrk.DoWork += (s, a) =>
            {
                Start();
            };

        wrk.RunWorkerAsync();
    }
    public event EventHandler Completed;

    private void Start()
    {
        auto1.WaitOne();
        auto2.WaitOne();

        Completed(this, EventArgs.Empty);
    }

    public AutoResetEvent auto1 = new AutoResetEvent(false);
    public AutoResetEvent auto2 = new AutoResetEvent(false);

    BackgroundWorker wrk = new BackgroundWorker();

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ServiceReference1.Service1Client clien = new SilverlightAsyncTest.ServiceReference1.Service1Client();

        clien.DoWorkCompleted += new EventHandler<SilverlightAsyncTest.ServiceReference1.DoWorkCompletedEventArgs>(clien_DoWorkCompleted);
        clien.DoWork2Completed += new EventHandler<SilverlightAsyncTest.ServiceReference1.DoWork2CompletedEventArgs>(clien_DoWork2Completed);

        clien.DoWorkAsync();
        clien.DoWork2Async();
    }

    void clien_DoWork2Completed(object sender, SilverlightAsyncTest.ServiceReference1.DoWork2CompletedEventArgs e)
    {
        Debug.WriteLine("2");
        auto1.Set();
    }

    void clien_DoWorkCompleted(object sender, SilverlightAsyncTest.ServiceReference1.DoWorkCompletedEventArgs e)
    {
        Debug.WriteLine("1");
        auto2.Set();
    }
}
jarek
+1  A: 

It could be done using the WaitHandle in the IAsyncResult returned by each async method.

The code is simple. In Silverlight I just do 10 service calls that will add an item to a ListBox. I'll wait until all the service calls end to add another message to the list (this has to run in a different thread to avoid blocking the UI). Also note that adding items to the list have to be done through the Dispatcher since they will modify the UI. There're a bunch of lamdas, but it's easy to follow.

 public MainPage()
        {
            InitializeComponent();
            var results = new ObservableCollection<string>();
            var asyncResults = new List<IAsyncResult>();
            resultsList.ItemsSource = results;
            var service = new Service1Client() as Service1;

            1.To(10).Do(i=>
                asyncResults.Add(service.BeginDoWork(ar =>
                    Dispatcher.BeginInvoke(() => results.Add(String.Format("Call {0} finished: {1}", i, service.EndDoWork(ar)))),
                    null))
            );

            new Thread(()=>
            {
                asyncResults.ForEach(a => a.AsyncWaitHandle.WaitOne());
                Dispatcher.BeginInvoke(() => results.Add("Everything finished"));
            }).Start();
        }

Just to help with the testing, this is the service

public class Service1
    {
        private const int maxMilliSecs = 500;
        private const int minMillisSecs = 100;
        [OperationContract]
        public int DoWork()
        {
            int millisSecsToWait = new Random().Next(maxMilliSecs - minMillisSecs) + minMillisSecs;
            Thread.Sleep(millisSecsToWait);
            return millisSecsToWait;
        }
    }
Miguel Madero
A: 

[where's the comment link?]
anyway the question I want ask on this answer is: 1.To(10).Do?????
Okay I found the Extensions here:
http://geekswithblogs.net/BlackRabbitCoder/archive/2010/04/21/more-fun-with-c-iterators-and-generators.aspx
but the extension for .Do is not included there and googling for the word "do" is pretty useless. If someone sees this can you point us to a reference for these extensions? thanks!
Okay, found it:
http://mfelicio.wordpress.com/2010/01/13/c-tips-ienumerablet-foreach-extension-method/

tobewan