No sé cuán "estándar" es mi idea, pero acabo de comenzar a utilizar algunas llamadas asincrónicas con WCF Data Services y Silverlight. En algunos casos, tenemos colecciones que son muy similares a las "colecciones" expuestas por el patrón Repositorio. Emitimos una consulta para obtener los artículos de un Servicio de datos WCF, pero luego cada elemento que se devuelve debe "cargarse" (es decir, cada elemento tiene un método Load que se ejecuta de forma asíncrona y puede emitir su propia consulta WCF Data Service) . Durante toda esta carga, cualquiera de nuestras interfaces gráficas que depende de los datos que se cargan (ciertas pestañas) se "bloquea" (se muestra el indicador de progreso) hasta que se carga. En algunos casos, tenemos que cargar dos colecciones porque una tiene una relación con la otra. Estamos utilizando un patrón de devolución de llamada con el Servicio de datos WCF, por lo que después de que se haya llamado a cada una de las devoluciones de llamada (cuando se cargan varias colecciones), sabemos que nuestra tarea de "carga" está completa.
Por lo tanto, la aplicación de nuestro modelo a su caso daría algo como esto (pseudocódigo bruto utilizando su código de ejemplo como punto de partida)
public class FooDataRepository
{
bool fooCompleted = false;
bool barCompleted = false;
int barsSaved = 0;
int barCount = 0;
private MyServiceReferenceClient Client { get; set; }
public void FooClass()
{
Client = new MyServiceReferenceClient();
Client.SaveFooCompleted += Client_SaveFooCompleted;
Client.SaveBarCompleted += Client_SaveBarCompleted;
}
private void Client_SaveFooCompleted(Object sender, EventArgs e)
{
fooCompleted = true;
if (barCompleted)
{
SaveCompleted();
}
}
private void Client_SaveBarCompleted(Object sender, EventArgs e)
{
Interlocked.Increment(barsSaved);
barCompleted = barsSaved == barCount;
if (fooCompleted)
{
SaveCompleted();
}
}
private void SaveCompleted()
{
//Do whatever you want to do when foo and all bars have been saved
}
public void SaveFoo(Foo foo)
{
fooCompleted = barCompleted = false;
barCount = foo.Bars.Count;
barsSaved = 0;
Client.SaveFooAsync(foo);
foreach (var bar in foo.Bars)
Client.SaveBarAsync(bar);
}
}
Para ser honesto, no estoy seguro de si se trata de un " buen "patrón o no. Estas llamadas son asincrónicas y tienen una devolución de llamada/evento que se llama/aumenta cuando el trabajo finaliza. Este patrón funciona lo suficientemente bien como para desactivar nuestra barra de progreso cuando se han cargado todos los datos.
No he usado mucho las tareas y no he usado Rx en absoluto, así que no sé cómo se aplican o no a este problema.
¡Buena suerte!
Es mucho más fácil si tiene acceso a los métodos no asíncronos (por ejemplo, SaveFoo() y SaveBar()). ¿Vos si? – Pat
Si quiere una respuesta suficiente para su caso, tendrá que proporcionar más información. No creo que exista un "patrón estándar" para lo que está describiendo, pero Tasks sería la respuesta más cercana. – Pat
Sí, hay métodos no asincrónicos creados cuando genera una referencia de servicio, sin embargo, el punto entero de la asincronización es no tener un gran bloque de espera para llamadas pesadas. Quiero poder actualizar al usuario en tiempo real a medida que se guarda el foo y se guardan todas las barras. – michael