2009-05-01 23 views
6

Parte de mi aplicación Silverlight requiere datos de tres solicitudes de servicio. Hasta ahora he estado encadenando las solicitudes para que uno complete los otros comienzos ... hasta el final de la cadena donde hago lo que tengo que hacer con los datos.Enhebrar varias llamadas asíncronas

Ahora, sé que no es el mejor método (!). He estado buscando en AutoResetEvent (enlace al ejemplo de MSDN) para enhebrar y luego sincronizar los resultados pero parece que esto no funciona con llamadas de servicio asincrónicas.

¿Alguien tiene alguna razón para dudar de este método o debería funcionar? ¡Muestras de código recibidas con gratitud!

Respuesta

7

Tome un vistazo a este ejemplo:

se disparará finalización evento e imprimir 'hecho' a la salida de depuración una vez que ambos servicios devueltos. La clave es que la espera de AutoResetEvents ocurre en el hilo de fondo.


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(); 
    } 
} 
+0

pregunta. tienes auto1 para DoWork2. Si tuviste 3 llamadas asincrónicas ¿simplemente agregaría auto3 y lo configuraría en el evento DoWork3Completed? – H20rider

3

Se podría hacer usando el WaitHandle en el IAsyncResult devuelto por cada método asíncrono.

El código es simple. En Silverlight solo hago 10 llamadas de servicio que agregarán un elemento a un ListBox. Esperaré hasta que todas las llamadas al servicio finalicen para agregar otro mensaje a la lista (esto tiene que ejecutarse en un hilo diferente para evitar el bloqueo de la IU). También tenga en cuenta que agregar elementos a la lista debe hacerse a través del Dispatcher, ya que modificarán la UI. Hay un montón de lamdas, pero es fácil de seguir.

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(); 
     } 

sólo para ayudar con las pruebas, este es el servicio

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; 
     } 
    } 
Cuestiones relacionadas